java之Thread

     * 线程:程序执行的一条路径,一个进程可以包含多条线程
     * 多线程并发执行可以提高程序的效率,可以同时完成多个工作
     *
     * JVM的启动至少启动了垃圾回收线程和主线程两个线程,所以是多线程;
     *
     * 多线程的实现方式有2中:
     *    1. 继承Thread
     *      1) 定义类继承Thread
     *      2) 重写run方法
     *      3) 把新线程要做的事写在run方法中
     *      4) 创建线程对象
     *      5) 开启新线程,内部会自动执行run方法

创建线程的第一种方式:继承Thread类

 1 public static void main(String[] args) {
 2 
 3         MyThread mt = new MyThread();   // 4) 创建线程对象
 4         mt.start();                     // 5) 开启新线程,内部会自动执行run方法
 5         for(int i = 0; i < 3000; i++) {
 6             System.out.println("bb");
 7         }
 8     }
 9 
10 }
11 
12 class MyThread extends Thread {     // 1) 定义类继承Thread
13     public void run() {             // 2) 重写run方法
14         for(int i = 0; i < 3000; i++) {     // 3) 把新线程要做的事写在run方法中
15             System.out.println("aaaaaaaaaaaaaaaa");
16         }
17     }
18 }

创建线程的第2中方式:实现Runnable接口     * 实现多线程的第2中方式,实现Runnable接口:
     *       1. 创建类实现Runnable接口
     *    2. 重写run方法,将要执行的代码写入run方法中
     *    3. 创建自定义类的对象
     *    4. 创建Thread类对象,将自定义对象传入
     *    5. Thread类对象调用start方法开启新线程,内部会自动调用Runnnable中的run方法

 1     public static void main(String[] args) {
 2 
 3         MyRunnable mr = new MyRunnable();
 4         Thread t = new Thread(mr);
 5         t.start();
 6         for(int i = 0; i < 3000; i++) {
 7             System.out.println("bbb");
 8         }
 9     }
10 
11 }
12 
13 class MyRunnable implements Runnable{
14 
15     @Override
16     public void run() {
17         for(int i = 0; i < 3000; i++) {
18             System.out.println("aaaaaaaaaaaa");
19         }
20     }
21     
22 }

 两种方式的区别:
     *    1. 查看源码的区别
     *        a. 继承Thread:由于子类重写了Thread类的run(),当调用start()方法时,直接找子类的run()方法
     *      b. 实现Runnable:构造函数中传入了Runnable的引用,成员变量记住了它,start()调用run()方法时内部判断成员变量Runnabe的引用是否为空,
     *         如果不为空,编译时看的是Runnable的run(),运行时执行的是子类的run()方法
     *         
     *    2. 实现使用上的区别:
     *      继承Thread:
     *         a.好处:可以直接使用Thread类中的方法,代码简单
     *         b.弊端:如果已经有了父类,就不能使用这种方法
     *      实现Runnable接口
     *         a.好处:即使自己定义的线程类有了父类也没有关系,因为有了父类可以实现接口,而且接口是可以多实现的
     *         b.弊端:不能直接使用Thread中的方法,需要先获取到线程对象后,才能得到Thread的方法,代码复杂  

使用匿名内部类实现多线程的两种方式:

 1 public static void main(String[] args) {
 2 
 3         new Thread() {
 4             public void run() {
 5                 for(int i = 0; i < 3000; i++) {
 6                     System.out.println("aaaaa");
 7                 }
 8             }
 9         }.start();
10         
11         new Thread(new Runnable() {
12             public void run() {
13                 for(int i = 0; i < 3000; i++) {
14                     System.out.println("bb");
15                 }
16             }
17         }).start();
18     }

给线程设置名称两种方式:

      1.  使用构造方法

      2.  使用setName()方法

 1 public class Demo4_ThreadMethod {
 2 
 3     /*
 4      * 设置线程名字的两种方法:
 5      *    1. 构造方法
 6      *    2. setName()方式
 7      */
 8     public static void main(String[] args) {
 9 
10         //demo1();
11         //demo2();
12         //demo3();
13         Thread t = new Thread() {
14             public void run() {
15                 System.out.println(this.getName() + "...ccc");
16             }
17         };
18         t.setName("王五");
19         t.start();
20     }
21 
22     /**
23      * 通过setName()方法给线程名赋值
24      */
25     public static void demo3() {
26         new Thread() {
27             public void run() {
28                 this.setName("李四");
29                 System.out.println(this.getName() + "...bb");
30             }
31         }.start();
32     }
33 
34     /**
35      * 通过构造方法给线程名称赋值
36      */
37     public static void demo2() {
38         new Thread("张三") {
39             public void run() {
40                 System.out.println(this.getName() + "...aaa");
41             }
42         }.start();
43     }
44 
45     /**
46      * 线程的名称是默认从0  Thread-0  依次往后累加
47      */
48     public static void demo1() {
49         new Thread() {
50             public void run() {
51                 System.out.println(this.getName() + "...aaa");  //Thread-0...aaa   
52             }
53         }.start();
54     }
55 
56 }

currentThread()方法和sleep()方法的使用:

 1 public class Demo5_CurrentThread {
 2 
 3     /*
 4      * CurrentThread()方法用来获取当前正在执行的线程
 5      * 
 6      * sleep()方法:会使线程暂时停一段时间
 7      */
 8     public static void main(String[] args) {
 9 
10         new Thread() {
11             public void run() {
12                 System.out.println(getName() + "...bbb");
13             }
14         }.start();
15         
16         new Thread(new Runnable() {
17             public void run() {
18                 Thread.currentThread().setName("李四");    
19                 //由于Runnable接口没有setName() 和 getName()方法,所以需要用currentThread()方法获取当前线程
20                 System.out.println(Thread.currentThread().getName() + "...aaa");
21             }
22         }).start();
23     }
24 
25 }

守护线程:

 1 public class Demo6_Daemon {
 2 
 3     /*
 4      * 守护线程
 5      */
 6     public static void main(String[] args) {
 7 
 8         Thread t1 = new Thread() {
 9             public void run() {
10                 for(int i = 0; i < 2; i++) {
11                     System.out.println(getName() + "...aaaa");
12                 }
13             }
14         };
15         
16         Thread t2 = new Thread() {
17             public void run() {
18                 for(int i = 0; i < 50; i++) {
19                     System.out.println(getName() + "...bb");
20                 }
21             }
22         };
23         
24         t2.setDaemon(true);    //设置t2为守护线程,当t1结束时t2也会随之结束
25         t1.start();
26         t2.start();
27     }
28 
29 }

join()方法的使用:

 1 public class Demo7_Join {
 2 
 3     /*
 4      * join()插队,等另外一个线程执行完毕后,再接着执行
 5      * join(1)插队1毫秒,1毫秒后两个线程继续交替执行
 6      */
 7     public static void main(String[] args) {
 8         final Thread t1 = new Thread() {
 9             public void run() {
10                 for(int i = 0; i < 10; i++) {
11                     System.out.println(getName() + "...aaa");
12                 }
13             }
14         };
15         
16         Thread t2 = new Thread() {
17             public void run() {
18                 for(int i = 0; i < 10; i++) {
19                     if(i==2) {
20                         try {
21                             //t1.join();             //匿名内部类要想调用局部变量,需要局部变量声明为final类型的
22                             t1.join(1);              //t1加入1毫秒,1毫秒后两个接着交替执行
23                         } catch (InterruptedException e) {
24                             e.printStackTrace();
25                         }
26                     }
27                     System.out.println(getName() + "...bb");
28                 }
29             }
30         };
31         t1.start();
32         t2.start();
33     }
34 }

同步的使用:

public class Demo8_Sychronized {

    /*
     * 同步代码块中需要传入的锁对象可以是任何对象,但是不能是匿名对象
     * 
     * 静态同步方法中的锁对象是类的字节码对象,如:demo.class
     */
    public static void main(String[] args) {

        Object o = new Object();
        while(true) {
            synchronized(o) {
                System.out.print("t");
                System.out.print("e");
                System.out.print("s");
                System.out.print("t");
                System.out.println();
            }
            
            synchronized(o) {
                System.out.print("a");
                System.out.print("b");
                System.out.print("c");
                System.out.print("d");
                System.out.println();
            }
        }
    }

}

练习:

       4个窗口同时售100张火车票

 1 继承Thread类的方式
 2 
 3 public class Demo9_Ticket {
 4 
 5     /*
 6      * 四个窗口同时卖出100张票
 7      */
 8     public static void main(String[] args) {
 9 
10         new Ticket().start();
11         new Ticket().start();
12         new Ticket().start();
13         new Ticket().start();
14     }
15 
16 }
17 
18 class Ticket extends Thread{
19     private static int ticket = 100;
20     //private static Object o = new Object();   如果是使用这种成员变量的方式,需要声明为静态变量
21     public void run() {
22         while(true) {
23             synchronized(Ticket.class) {
24                 if(ticket <= 0) {
25                     break;
26                 }
27                 try {
28                     Thread.sleep(10);
29                 } catch (InterruptedException e) {
30                     e.printStackTrace();
31                 }
32                 System.out.println(getName() + "...第" + ticket-- + "张票");
33             }
34         }
35     }
36 }
37 
38 ------------------------------------------
39 
40 实现Runnable接口的方式:
41 
42 public class Demo10_Ticket {
43 
44     /*
45      * 使用实现Runnable接口进行四个窗口同步卖票
46      */
47     public static void main(String[] args) {
48 
49         Ticket1 t = new Ticket1();
50         new Thread(t).start();
51         new Thread(t).start();
52         new Thread(t).start();
53         new Thread(t).start();
54         
55         /*Ticket1 t1 = new Ticket1();
56         Thread t2 = new Thread(t1);
57         t2.start();
58         t2.start();
59         t2.start();
60         t2.start();
61         一个线程只能启动一次,调用一次start()方法
62         */
63     }
64 
65 }
66 
67 class Ticket1 implements Runnable{
68 
69     private int ticket = 100;
70     @Override
71     public void run() {
72         while(true) {
73             synchronized(this) {
74                 if(ticket<=0) {
75                     break;
76                 }
77                 try {
78                     Thread.sleep(10);
79                 } catch (InterruptedException e) {
80                     e.printStackTrace();
81                 }
82                 System.out.println(Thread.currentThread().getName() + "...第" + ticket-- + "张票");
83             }
84         }
85     }
86     
87 }

 

posted @ 2018-07-15 20:40  just_do_it_!  阅读(196)  评论(0编辑  收藏  举报