线程

1.线程的生命周期

 2.新建线程

实现Runnable接口中的run()方法

 1 public class User implements Runnable {
 2 
 3     @Override
 4     public void run() {
 5         System.out.println("run");
 6     }
 7 
 8     public static void main(String[] args) {
 9         Thread t = new Thread(new User());
10         t.start();
11     }
12 }

3.中断线程

  • 为线程设置标志位,在run()方法中设定结束条件,在其他线程修改了标志位以后,退出线程。

不要使用stop()方法结束线程,使用stop会使线程释放它持有的锁,导致数据的不一致性。如:用线程读写user,这个user本来id=1,name=1,写线程使用stop方法结束,导致刚写完user的id=1线程的锁就被释放了,此时有一个线程读取了这个user,有可能会读出user的id=1,name=0这种不一致结果。

 1 package com.company;
 2 public class User implements Runnable {
 3     public volatile boolean exit = false;
 4     @Override
 5     public void run() {
 6         while (true){
 7             if (exit) {
 8                 System.out.println("exit");
 9                 break;
10             }
11             System.out.println("running");
12         }
13     }
14 
15     public static void main(String[] args) throws InterruptedException {
16         User u = new User();
17         Thread t = new Thread(u);
18         t.start();
19         Thread.sleep(10);
20         u.exit = true;
21     }
22 }
  • 使用interrupt()方法中断线程,不是立即中断,而是告诉目标线程,有人希望你退出了。

interrupt()相当于设置了中断标志,需要在运行的线程当中捕获这个标志并进行处理。

下面的程序每隔0.5秒输出一个数字,5秒后设置中断,运行的线程处理中断的逻辑是退出线程,因此输出到9程序退出。

注意sleep()方法在休眠过程中,被中断会抛出中断异常,抛出中断异常后会清除中断标志,如果不在sleep()的中断块中处理中断逻辑,需要重新设置中断标志。

 1 package com.company;
 2 
 3 public class User implements Runnable {
 4     private volatile int i = 0;
 5     @Override
 6     public void run() {
 7         while(true){
 8             if(Thread.currentThread().isInterrupted()){
 9                 System.out.println("exit");
10                 break;
11             }
12             try {
13                 Thread.sleep(500);
14             } catch (InterruptedException e) {
15                 //e.printStackTrace();
16                 Thread.currentThread().interrupt();
17             }
18             System.out.println(i++);
19         }
20     }
21 
22     public static void main(String[] args) throws InterruptedException {
23         Thread t = new Thread(new User());
24         t.start();
25         Thread.sleep(5000);
26         t.interrupt();
27     }
28 }

 4.wait()和notify()

wait()和notify()方法是Object的方法,这2个方法用来完成线程之间的协作。

wait()和notify()方法需要持有对象的锁,因此必须放在synchronized块中。

某个线程t1内调用一个对象object.wait()方法,会将t1线程加入到object的等待队列中,等待被notify(),注意notify()是随机唤醒,不是顺序唤醒。

 1 package com.company;
 2 
 3 import java.text.SimpleDateFormat;
 4 
 5 public class Main {
 6     private static Main obj = new Main();
 7     public static class WaitThread extends Thread{
 8 
 9         @Override
10         public void run() {
11             synchronized (obj){
12                 System.out.println("等线程启动!");
13                 try {
14                     obj.wait();
15                 } catch (InterruptedException e) {
16                 }
17                 SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
18                 System.out.println(df.format(System.currentTimeMillis()));
19                 System.out.println("等线程结束!");
20             }
21         }
22     }
23     public static class NotifyThread extends Thread{
24         @Override
25         public void run() {
26             synchronized (obj){
27                 SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
28                 System.out.println(df.format(System.currentTimeMillis()));
29                 System.out.println("唤醒线程启动!");
30                 obj.notify();
31                 System.out.println("唤醒!");
32                 try {
33                     Thread.sleep(2000);
34                 } catch (InterruptedException e) {
35                     e.printStackTrace();
36                 }
37                 System.out.println("释放锁!");
38             }
39         }
40     }
41     public static void main(String[] args) {
42         Thread t1 = new WaitThread();
43         Thread t2 = new NotifyThread();
44         t1.start();
45         t2.start();
46 
47     }
48 }

 5.join

join使当前线程等待某个线程执行完了以后在执行下面的代码。

package com.company;

public class User implements Runnable {
    public static volatile int i = 0;
    @Override
    public void run() {
        for(;i<10000;i++);
    }

    public static void main(String[] args) throws InterruptedException {
        Thread t = new Thread(new User());
        t.start();
        t.join();
        System.out.println(i);
    }
}

注释了join的话,有可能会输出0,表示t线程还没有执行完,主线程就输出了。

6.线程组

把线程加到不同的组里,方便管理。

 1 package com.company;
 2 
 3 public class User implements Runnable {
 4     @Override
 5     public void run() {
 6         System.out.println(Thread.currentThread().getThreadGroup().getName() + Thread.currentThread().getName());
 7     }
 8 
 9     public static void main(String[] args) throws InterruptedException {
10         ThreadGroup gp = new ThreadGroup("printgp");
11         Thread t1 = new Thread(gp,new User(),"t1");
12         Thread t2 = new Thread(gp,new User(),"t2");
13         t1.start();
14         t2.start();
15     }
16 }

7.守护线程

守护线程是为用户线程默默服务的线程,如果系统里只有守护线程,那么程序会退出。

守护线程不停的打印i的值,但是用户线程main在3秒以后退出,所以main线程结束后,守护线程也结束了。

 1 package com.company;
 2 
 3 public class User implements Runnable {
 4     @Override
 5     public void run() {
 6        int i = 0;
 7        while(true){
 8            System.out.println(i++);
 9            try {
10                Thread.sleep(1000);
11            } catch (InterruptedException e) {
12                e.printStackTrace();
13            }
14        }
15     }
16 
17     public static void main(String[] args) throws InterruptedException {
18         Thread t = new Thread(new User());
19         t.setDaemon(true);
20         t.start();
21         Thread.sleep(3000);
22     }
23 }

8.线程优先级

线程优先级从1-10,在抢占资源时,高优先级的线程会比低优先级的线程更容易抢占到资源。

经过几秒钟的实验,优先级高的能比优先级低的抢占更多次资源。

 1 package com.company;
 2 
 3 public class User implements Runnable {
 4     public static volatile int lowNum = 0;
 5     public static volatile int maxNum = 0;
 6     public static volatile int runNum = 0;
 7     @Override
 8     public void run() {
 9         while(true){
10             synchronized (User.class){
11                 runNum++;
12                 if(Thread.currentThread().getName() == "low")
13                     lowNum++;
14                 else maxNum++;
15             }
16             System.out.println("总比赛次数"+runNum+",low获胜次数"+lowNum+",max获胜次数"+maxNum);
17         }
18     }
19 
20     public static void main(String[] args) throws InterruptedException {
21         Thread t1 = new Thread(new User(),"low");
22         Thread t2 = new Thread(new User(),"max");
23         t1.setPriority(Thread.MIN_PRIORITY);
24         t2.setPriority(Thread.MAX_PRIORITY);
25         t1.start();
26         t2.start();
27     }
28 }

 9.synchronized

synchronized关键字把某段代码设定为blocked状态,blocked状态的代码块,一次只能有一个线程进入,从而使某些公共资源对所有的线程来讲都是同步的。

未进行同步的代码,最终输出的i值都到不了100000000.

package com.company;

public class User implements Runnable {
    private static User user = new User();
    private static int i = 0;
    @Override
    public void run() {
        for (int j = 0; j < 100000000; j++) {
            i++;
        }
        System.out.println(i);
    }

    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(new User());
        Thread t2 = new Thread(new User());
        t1.start();
        t2.start();
    }
}

三种方法同步

  • 同步实例对象
 1 package com.company;
 2 
 3 public class User implements Runnable {
 4     static User user = new User();
 5     static int i = 0;
 6     @Override
 7     public void run() {
 8         //对实例对象user同步
 9         synchronized (user){
10             for (int j = 0; j < 10000000; j++) {
11                 i++;
12             }
13             System.out.println(i);
14         }
15     }
16 
17     public static void main(String[] args) throws InterruptedException {
18         //保证2个线程使用同一个实例对象创建
19         Thread t1 = new Thread(user);
20         Thread t2 = new Thread(user);
21         t1.start();
22         t2.start();
23     }
24 }
  • 同步实例方法
 1 package com.company;
 2 
 3 public class User implements Runnable {
 4     static User user = new User();
 5     static int i = 0;
 6     //使用synchronized同步实例方法
 7     public synchronized void increase(){
 8         for (int j = 0; j < 10000000; j++) {
 9             i++;
10         }
11         System.out.println(i);
12     }
13     @Override
14     public void run() {
15         increase();
16     }
17 
18     public static void main(String[] args) throws InterruptedException {
19         //保证2个线程使用同一个实例对象创建
20         Thread t1 = new Thread(user);
21         Thread t2 = new Thread(user);
22         t1.start();
23         t2.start();
24     }
25 }
  • 同步类
 1 package com.company;
 2 
 3 public class User implements Runnable {
 4     static int i = 0;
 5     @Override
 6     public void run() {
 7         //同步类
 8         synchronized (User.class) {
 9             for (int j = 0; j < 10000000; j++) {
10                 i++;
11             }
12             System.out.println(i);
13         }
14     }
15 
16     public static void main(String[] args) throws InterruptedException {
17         //保证2个线程使用同一个实例对象创建
18         Thread t1 = new Thread(new User());
19         Thread t2 = new Thread(new User());
20         t1.start();
21         t2.start();
22     }
23 }
原文地址:https://www.cnblogs.com/vshen999/p/12388813.html