zoukankan      html  css  js  c++  java
  • 线程

    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 }
  • 相关阅读:
    我要当伴娘
    Oracle SCN与时间的相互转换
    解决物理standby 归档日志损坏ORA00334
    Oracle块修改跟踪功能
    八月九日学习报告
    八月十三日学习报告
    八月七日学习报告
    八月十二日学习报告
    八月六日学习报告
    八月十日学习报告
  • 原文地址:https://www.cnblogs.com/vshen999/p/12388813.html
Copyright © 2011-2022 走看看