java中创建线程的三种方法

 

Java使用Thread类代表线程,所有的线程对象都必须是Thread类或其子类的实例。Java可以用三种方式来创建线程,如下所示:

1)继承Thread类创建线程

2)实现Runnable接口创建线程

3)使用Callable和Future创建线程

 

一.概念及特点

    1.概念

进程:计算机运行的应用程序。(多进程作用:提高CPU的使用率,不提高速度);

          线程;一个进程中的执行场景,一个进程可以包多个线程。(多线程作用:提高应用程序的使用率,不提高速度)。

2.内存特点

          进程和进程之间的内存是独立的;

          线程和线程共享“堆内存的方法区内存”,栈内存是独立的,一个线程一个栈。

    3.java程序的运行原理

         Java命令启动Java虚拟机,启动JVM,等同于启动了一个应用程序,、表示启动了一个进程,该进程会自动启动一个“主线程”,然后主线程去调用某个类的main方法,所 以main方法运行在主线程中。

二.线程的创建和启动

  1.实现多线程的第一种方式: 

         第一步: 继承Java.lang.Thread

         第二步;重写run方法

例:

Java 一个nio可以最多处理多少请求而不会卡顿_优先级

Java 一个nio可以最多处理多少请求而不会卡顿_System_02

1 class  Threadtest01
 2 {
 3     public static void main(String[] args)   //main方法在主线程
 4     {
 5         //1.创建线程
 6         Thread t = new p();
 7         //2.启动线程
 8         t.start();      /*启动t线程,执行后,t线程瞬间结束,JVM再分配一个新的栈给t线程
 9                           run方法不需要手动调用,系统线程启动之后自动调用run方法。*/
10     
11        for(int i=0;i<100;i++)   //在主线程中运行
12         {
13            System.out.println("main....."+i);
14         }
15     }
16 }
17 /*
18    在多线程中,main方法结束后只是主线程踪没有方法栈帧了,但
19    其他线程中或者其他栈中还有栈帧,main方法结束,程序可能还在运行
20 */
21 
22 //3.定义一个线程
23 class p extends Thread
24 {
25     //重写run方法
26     public void run ()
27     {
28          for(int i=0;i<100;i++)
29         {
30            System.out.println("run...."+i);
31         }
32     }
33 }
34 /*
35 运行部分结果如下:
36 main.....0
37 main.....1
38 main.....2
39 run....0
40 main.....3
41 run....1
42 main.....4
43 run....2
44 main.....5
45 run....3
46 main.....6
47 run....4
48 main.....7
49 run....5
50 main.....8
51 run....6
52 */

View Code

上述代码的图解如下:

Java 一个nio可以最多处理多少请求而不会卡顿_java_03

 2.实现多线程的第二种方式:

           第一步:写一个实现类java,lang.Runnable;接口

          第二步:实现run方法

     例:

Java 一个nio可以最多处理多少请求而不会卡顿_优先级

Java 一个nio可以最多处理多少请求而不会卡顿_System_02

1 package test;
 2 
 3 class Main 
 4 {
 5     public static void main(String[] args) 
 6     {
 7         //创建线程
 8         Thread t = new Thread(new p());
 9         //启动线程
10         t.start();
11         for(int i = 0;i<100;i++)
12               System.out.println("mian..."+i);
13         
14     }
15 }
16 //优先,一个类实现接口之外保留了类的继承
17 class p implements Runnable
18 {
19     public void run()
20     {
21         for(int i = 0;i<100;i++)
22           System.out.println("run..."+i);
23     }
24 }
25 /*
26  * 部分运行结果:
27  * run...8
28 mian...10
29 run...9
30 mian...11
31 run...10
32 mian...12
33 run...11
34 mian...13
35 run...12
36  */

View Code

.线程的生命周期

 线程生命周期状态图:

                

Java 一个nio可以最多处理多少请求而不会卡顿_java_06

四.线程的调度与控制

   1.线程优先级     

java虚拟机主要负责则线程的调度,获取CPU的使用权,目前有两种调度模型:分时调度模型和抢占调度模型;java使用抢占调度模型。

分时调度模型:所有线程轮流使用CPU的使用权,平均分配给每个线程占用CPU的时间片。

 

抢占调度模型:优先让优先级高的线程使用CPU,如果线程的优先级相同,那么随机选择一个,优先极高的线程获得的CPU时间片相对多些。

      例:

Java 一个nio可以最多处理多少请求而不会卡顿_优先级

Java 一个nio可以最多处理多少请求而不会卡顿_System_02

1 /*
 2    线程优先级高的获取的时间片相对高
 3 */
 4 class  Threadtest04
 5 {
 6     public static void main(String[] args) 
 7     {
 8         //线程优先级
 9         System.out.println(Thread.MAX_PRIORITY); //10 优先级最高
10         System.out.println(Thread.MIN_PRIORITY); //1  优先级最低
11         System.out.println(Thread.NORM_PRIORITY); //5  默认优先级
12         Thread t1 = new P();
13         t1.setName("t1");
14 
15         Thread t2 = new P();
16         t2.setName("t2");
17 
18         System.out.println(t1.getPriority()); //默认优先级为5
19         System.out.println(t2.getPriority()); //默认优先级为5
20         //设置优先级
21         t1.setPriority(4);
22         t2.setPriority(9);
23 
24         System.out.println(t1.getPriority()); //默认优先级为5
25         System.out.println(t2.getPriority()); //默认优先级为5
26         //启动线程
27         t1.start();
28         t2.start();
29     }
30 }
31 
32 class P extends Thread
33 {
34     public void run()
35     {
36         for(int i=0;i<10;i++)
37         {
38             System.out.println(Thread.currentThread().getName()+"..."+i);
39         }
40     }
41 }
42 /*
43 运行结果:
44 10
45 1
46 5
47 5
48 5
49 4
50 9
51 t1...0
52 t2...0
53 t1...1
54 t2...1
55 t1...2
56 t2...2
57 t1...3
58 t2...3
59 t1...4
60 t2...4
61 t1...5
62 t2...5
63 t1...6
64 t2...6
65 t1...7
66 t2...7
67 t1...8
68 t2...8
69 t1...9
70 t2...9
71 请按任意键继续. . .
72 
73 
74 */

View Code

   

    2.sleep方法

     sleep和wait的区别:

      (1)所属类不同  

               Thread.sleep() ;   Object.wait()

      (2)对于线程已经占有资源的处理

              sleep在休息的时候,不释放资源 ; wait在等待的时候释放自己占用的资源

例:

Java 一个nio可以最多处理多少请求而不会卡顿_优先级

Java 一个nio可以最多处理多少请求而不会卡顿_System_02

1 /*
 2   1.thread.sleep(毫秒)
 3   2.sleep方法是一个静态方法
 4   3.该方法作用:阻塞当前线程,将CPU让给其他线程
 5 */
 6 class Threadtest05 
 7 {
 8     public static void main(String[] args) throws InterruptedException
 9     {
10         Thread t1 = new P();
11         t1.setName("t1");
12         t1.start();
13         Thread.sleep(5000);
14         //t1.interrupt();打断线程的睡眠
15         for(int i = 0;i<10;i++)
16         {
17             System.out.println(Thread.currentThread().getName()+".."+i);
18             Thread.sleep(500);//阻塞主线程0.5秒
19         }
20     }
21 }
22 
23 class P extends Thread
24 {
25     //被重写的方法不能抛出异常,在run方法的声明为置上不能呢使用Throws,
26     public void run()
27     {
28         for(int i = 0;i<10;i++)
29         {
30             
31             try{
32                 Thread.sleep(1000);//让当前线程阻塞1s
33             }catch(InterruptedException e)
34             {
35                 e.printStackTrace();
36             }
37             System.out.println(Thread.currentThread().getName()+".."+i);
38         }
39     }
40 }
41 /*
42   运行结果:
43   main..0
44 t1..0
45 main..1
46 t1..1
47 main..2
48 main..3
49 main..4
50 t1..2
51 main..5
52 t1..3
53 main..6
54 main..7
55 t1..4
56 main..8
57 main..9
58 t1..5
59 t1..6
60 t1..7
61 t1..8
62 t1..9
63 请按任意键继续. . .
64 
65 */

View Code

 

    3.yield方法

          使用yield方法,与sleep方法类似,不能由用户指定暂停多长时间,并且yield方法只能让同优先级的线程由执行机会,让位时间不固定。静态方法。

    4.Join方法

           合并线程

 五.线程的同步(加锁)

    1.基本概念及特点

       (1)概念:

            a.线程同步,是指某一个时刻,只允许一个线程访问共享资源,线程同步实际上是对对象加锁,如果对象中的方法都是同步方法,那么某一时刻只能执 行一个方法,采用线程同步解决以上问题;  为了数据安全,尽管应用程序的使用效率降低,但是为了数据安全,必须加入线程同步机制,线程同步机制使程序等同于单线程。

              b.异步编程模型:多个线程分别执行,各线程互不影响。

              c.同步编程模型:多个线程执行只有一个线程执行结束才能执行另一个线程。(作用:达到数据安全)

      (2)使用线程同步机制的条件:

              a:必须是多线程环境

              b:多线程环境共享一个数据

              c:共享的数据涉及到数据的修改

  2.举例

 例1:(对象锁,方法一,控制精确,常用)

Java 一个nio可以最多处理多少请求而不会卡顿_优先级

Java 一个nio可以最多处理多少请求而不会卡顿_System_02

1 /*
 2    模拟银行取款系统:对于同一个账号,用两个线程同时对其取款。
 3 */
 4 class Threadtest06
 5 {
 6     public static void main(String[] args) 
 7     {
 8        //创建公共账号
 9        Account act = new Account("账号sss",10000);
10        //创建两个线程对同一个账户取款
11        Thread t1 = new Thread(new P(act));
12        Thread t2 = new Thread(new P(act));
13        t1.start();
14        t2.start();
15     }
16 }
17 //取款线程
18 class P implements Runnable
19 {
20     //账户
21     Account act;
22     P(Account act)
23     {
24         this.act = act;
25     }
26     public void run()
27     {
28         act.withdraw(2000);
29         System.out.println("取款成功,余额为:"+act.getBalance());
30     }
31 
32 }
33 //账户
34 class Account
35 {
36     private String action;
37     private double balance;
38     public Account(){}
39     public Account(String action,double balance){
40       this.action = action;
41       this.balance = balance;
42     }
43     public void setAction(String action)
44     {
45         this.action = action;
46     }
47     
48     public void setBalance(double balance)
49     {
50         this.balance = balance;
51     }
52     public String getAction(String action)
53     {
54         return action;
55     }
56     public double getBalance()
57     {
58         return balance;
59     }
60     public void withdraw(double money)
61     {
62         synchronized(this){  //this表示共享对象
63            double after = balance - money;
64            try{
65            Thread.sleep(1000);
66            }catch(Exception e){}
67            this.setBalance(after);
68         }
69     }
70 }
71 
72 /*
73 运行结果:
74 取款成功,余额为:8000.0
75 取款成功,余额为:6000.0
76 请按任意键继续. . .
77 
78 */

View Code

 上例原理:   t1线程执行到synchronized关键字处,就会去找this对象锁,如果找到this对象锁,就回进入同步语句块中执行,当同步语句块中的代码执行结束后,

                 t1线程归还this对象锁。在t1线程执行同步语句块的过程中,如果t2线程也过来执行此代码,也遇到synchronized关键字,所以也去找this对象锁,但是

                 该对象锁被t1线程持有,只能等待this对象的归还。

 例2;synchronized关键字添加到成员方法上,线程拿到的扔是this的对象锁(对象锁,方法二,执行效率低)

Java 一个nio可以最多处理多少请求而不会卡顿_优先级

Java 一个nio可以最多处理多少请求而不会卡顿_System_02

1 /*
 2    模拟银行取款系统:对于同一个账号,用两个线程同时对其取款。
 3 */
 4 class Threadtest06
 5 {
 6     public static void main(String[] args) 
 7     {
 8        //创建公共账号
 9        Account act = new Account("账号sss",10000);
10        //创建两个线程对同一个账户取款
11        Thread t1 = new Thread(new P(act));
12        Thread t2 = new Thread(new P(act));
13        t1.start();
14        t2.start();
15     }
16 }
17 //取款线程
18 class P implements Runnable
19 {
20     //账户
21     Account act;
22     P(Account act)
23     {
24         this.act = act;
25     }
26     public void run()
27     {
28         act.withdraw(2000);
29         System.out.println("取款成功,余额为:"+act.getBalance());
30     }
31 
32 }
33 //账户
34 class Account
35 {
36     private String action;
37     private double balance;
38     public Account(){}
39     public Account(String action,double balance){
40       this.action = action;
41       this.balance = balance;
42     }
43     public void setAction(String action)
44     {
45         this.action = action;
46     }
47     
48     public void setBalance(double balance)
49     {
50         this.balance = balance;
51     }
52     public String getAction(String action)
53     {
54         return action;
55     }
56     public double getBalance()
57     {
58         return balance;
59     }
60     public  synchronized void withdraw(double money)
61     {
62         
63            double after = balance - money;
64            try{
65            Thread.sleep(1000);
66            }catch(Exception e){}
67            this.setBalance(after);
68         
69     }
70 }
71 
72 /*
73 运行结果:
74 取款成功,余额为:8000.0
75 取款成功,余额为:6000.0
76 请按任意键继续. . .
77 
78 */

View Code

  (另:StirngBuffer  Vector Hashtable 是线程安全的 )

 例3:(类锁)

Java 一个nio可以最多处理多少请求而不会卡顿_优先级

Java 一个nio可以最多处理多少请求而不会卡顿_System_02

1 /*
 2    类锁,类只有一个,所以类锁只有一个,与对象无关
 3 */
 4 class Threadtest07 
 5 {
 6     public static void main(String[] args) throws Exception
 7     {
 8         Thread t1 = new Thread(new P());
 9         Thread t2 = new Thread(new P());
10         t1.setName("t1");
11         t2.setName("t2");
12         t1.start();
13         Thread.sleep(1000);
14         t2.start();
15     }
16 }
17 
18 class P implements Runnable
19 {
20     public void run()
21     {
22         if("t1".equals(Thread.currentThread().getName()))
23          MyClass.m1();
24         if("t2".equals(Thread.currentThread().getName()))
25          MyClass.m2();
26     }
27 }
28 
29 class MyClass
30 {
31     //将synchronized添加到静态方法上,线程执行到此方法会找到类锁
32     public synchronized static void m1()
33     {
34         try{
35             Thread.sleep(10000);
36         }catch(Exception e){}
37         System.out.println("m1");
38     }
39     /*  不会等m1结束,该方法没有被synchronized修饰
40     public static void m2()
41     {
42      System.out.println("m2");
43     }
44     */
45     //m2方法等m1结束之后才能执行,线程执行到该代码需要类锁,二类锁只有一个
46     public synchronized static void m2()
47     {
48      System.out.println("m2");
49     }
50 }

View Code

六.死锁

   例:  

Java 一个nio可以最多处理多少请求而不会卡顿_优先级

Java 一个nio可以最多处理多少请求而不会卡顿_System_02

1 /*
 2    死锁
 3 */
 4 class DeadLook
 5 {
 6     public static void main(String[] args) 
 7     {
 8        Object o1 = new Object();    
 9        Object o2 = new Object();
10        
11        Thread t1 = new Thread(new T1(o1,o2));
12        Thread t2 = new Thread(new T2(o1,o2));
13        t1.start();
14        t2.start();
15     }
16 }
17 
18 class T1 implements Runnable
19 {
20     Object o1;
21     Object o2;
22     T1(Object o1,Object o2)
23     {
24         this.o1 = o1;
25         this.o2 = o2;
26     }
27     public void run()
28     {
29         synchronized(o1)
30         {
31             try{Thread.sleep(1000);}catch(Exception e){}
32             synchronized(o2)
33             {
34                 System.out.println("t1");
35             }
36         }
37     }
38 }
39 class T2 implements Runnable
40 {
41     Object o1;
42     Object o2;
43     T2(Object o1,Object o2)
44     {
45         this.o1 = o1;
46         this.o2 = o2;
47     }
48     public void run()
49     {
50         synchronized(o2)
51         {
52             try{Thread.sleep(1000);}catch(Exception e){}
53             synchronized(o1)
54             {
55                 System.out.println("t2");
56             }
57         }
58     }
59 }

View Code

七.守护线程

         从线程的分类上可以分为:用户线程和守护线程,所有的用户线程结束生命周期,只有一个用户线程存在,那么守护线程就不会结束,Java中的垃圾回收器就

是一个守护线程,只有应用程序中所有的线程结束,它才会结束。 

    例:

Java 一个nio可以最多处理多少请求而不会卡顿_优先级

Java 一个nio可以最多处理多少请求而不会卡顿_System_02

1 /*
 2    守护线程:
 3    所有的用户线程结束,守护线程才会结束,守护线程是一个无限循环执行的。
 4 */
 5 class  Threadtest08
 6 {
 7     public static void main(String[] args) throws Exception  
 8     {
 9         Thread t1 = new P();
10         t1.setName("t1");
11         t1.setDaemon(true);//将用户线程修改为守护线程
12         t1.start();
13         //主线程
14         for(int i = 0;i < 10; i++)
15         {
16            System.out.println(Thread.currentThread().getName()+".."+i);
17            Thread.sleep(1000);
18         }
19     }
20 }
21 
22 class P extends Thread
23 {
24    public void run()
25     {
26        int i = 0;
27        while(true)
28         {
29            i++;
30            System.out.println(Thread.currentThread().getName()+".."+i);
31            try{Thread.sleep(1000);}catch(Exception e){}
32         }
33     }
34 }
35 /*
36 运行结果:
37 main..0
38 t1..1
39 t1..2
40 main..1
41 t1..3
42 main..2
43 main..3
44 t1..4
45 main..4
46 t1..5
47 main..5
48 t1..6
49 main..6
50 t1..7
51 main..7
52 t1..8
53 main..8
54 t1..9
55 main..9
56 t1..10
57 请按任意键继续. . .
58 
59 
60 */

View Code

 八.Timer定时器

     作用:每隔一段固定的时间执行一段代码

     例:

Java 一个nio可以最多处理多少请求而不会卡顿_优先级

Java 一个nio可以最多处理多少请求而不会卡顿_System_02

1 /*
 2    定时器
 3 */
 4 import java.text.*;
 5 import java.util.*;
 6 class  Timertest
 7 {
 8     public static void main(String[] args) throws Exception
 9     {
10         //创建定时器
11         Timer t = new Timer();
12         //指定定时任务
13         t.schedule(new LogTimerTask(),new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS").parse("2017-04-21 11:42:00 000"),10*1000);
14 
15     }
16 }
17 //指定任务
18 class LogTimerTask extends TimerTask
19 {
20     public void run()
21     {
22         System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS").format(new Date()));
23     }
24 }

View Code