zoukankan      html  css  js  c++  java
  • Java中线程总结

    本文简要介绍在 Java 世界中, 线程相关知识。主要包含 线程的创建与销毁;线程安全与同步;线程通讯;注意本文没有什么高深新知识,只缘起前段时间在翻看项目代码的时候,发现有些同学对此有诸多误解,故在此稍微整理一下,以帮助类似同学,同时警醒一下自己。

    1.  线程的创建和销毁;

    a) .创建线程可以通过继承 Thread 类 或 实现 Runnable 接口, 并重写 run() 方法, 其中的run() 方法即是本线程需要执行的内容.

    b). 相比于单独继承 Thread ,Runnable接口配合 Thread 实现会更灵活,并可以通过共享一个Runnable接口实例,在Thread中共享资源.

    c). 至于线程销毁,不推荐使用 Thread.Stop()方法, 此方法在使用不当情况下会出现死锁,更多的时候推荐在run()方法中使用额外变量(或条件)结束此方法即可.

     2. 线程安全与同步;

    a). 对于需要遵循ACID原子一致性的代码段, 可以通过 synchronized(lockKey){} 代码块锁定;

    b). 同时 synchronized 关键字可以用来修饰一个方法,表示整个方法都需要遵循ACID原子一致性,值得注意的是,此时其实的lockKey等效于this关键字;

    b). 在锁定的代码块中推荐再进行一次必要的条件判断。

      3. 线程通讯,在java的世界中可以借助 wait() notify() notifyAll() 这三个方法来完成,这三个方法定义在Object类中,因此所有的对象都可以使用.

      4.下面通过简单的几个代码片段来加以说明

      a). 演示线程创建与销毁,及线程安全与同步

     1 public class ThreadTest implements Runnable {
     2     private boolean stop;                   //是否需要停止运行
     3     private int tiketCount = 100000;        //总票数
     4     private boolean lockTypeIsMethod = true; //是否是提供方法锁定还是代码块
     5 
     6     public boolean isStop() {
     7         return stop;
     8     }
     9     public void setStop(boolean stop) {
    10         this.stop = stop;
    11     }
    12 
    13     public boolean isLockTypeMethod() {
    14         return lockTypeIsMethod;
    15     }
    16     public void setLockTypeIsMethod(boolean lockTypeIsMethod) {
    17         this.lockTypeIsMethod = lockTypeIsMethod;
    18     }
    19 
    20     @Override
    21     public void run() {
    22         while (tiketCount > 0 && !stop) {
    23             try {
    24                 Thread.sleep(50);    //延时,方便演示
    25             } catch (InterruptedException e) {
    26                 e.printStackTrace();
    27             }
    28 
    29             //如果是通过锁定方法
    30             if (lockTypeIsMethod) {
    31                 sale();
    32             } else {
    33                 synchronized (this) {
    34                     if (tiketCount > 0 && !stop) {
    35                         System.out.println("使用代码块锁定:threadId="
    36                                 + Thread.currentThread().getName() + ",ticketNO:" + tiketCount--);
    37                     }
    38                 }
    39             }
    40         }
    41     }
    42 
    43     public synchronized void sale() {
    44         if (tiketCount > 0 && !stop) {
    45             System.out.println("使用方法锁定:threadId="
    46                     + Thread.currentThread().getName() + ",ticketNO:" + tiketCount--);
    47         }
    48     }
    49 }
    线程定义类
     1 public static void main(String[] args) throws InterruptedException {
     2     ThreadTest threadTest = new ThreadTest();   //共享变量ThreadTest
     3     //启用四个线程
     4     new Thread(threadTest).start();
     5     new Thread(threadTest).start();
     6     new Thread(threadTest).start();
     7     new Thread(threadTest).start();
     8     //模拟设置共享变量,
     9     // 1.交替使用方法体和代码块来进行线程同步实验
    10     // 2.模拟线程停止
    11     for (int i = 0; i < 100; i++) {
    12         Thread.sleep(1000);
    13         threadTest.setLockTypeIsMethod(i % 2 == 0);
    14         if (i == 50) {
    15             threadTest.setStop(true);
    16         }
    17     }
    18 }
    调用端

      b). 演示线程通讯,本处模拟两个线程以生产和消费者角色读写一个集合的示例,其中当集合中有数据的时候通知消费者处理数据,处理完后通知生产者往集合中放入数据

     1 //数据仓库
     2 public class DataRepository {
     3     private List<String> data = new ArrayList<>();
     4     private boolean hasData;
     5 
     6     public boolean HasData() {
     7         return hasData;
     8     }
     9 
    10     public void setHasData(boolean hasData) {
    11         this.hasData = hasData;
    12     }
    13 
    14     //放入数据
    15     public synchronized void put(List<String> data) throws InterruptedException {
    16         //生产者放入数据的时候,如果还有数据则等待.
    17         if (hasData) {
    18             wait();
    19         }
    20         this.data = data;
    21         hasData = true;
    22         //放入完毕后通知消费者
    23         notify();
    24     }
    25 
    26     //读取数据
    27     public synchronized List<String> get() throws InterruptedException {
    28         //没有数据则等待
    29         if (!hasData) {
    30             wait();
    31         }
    32         //获取数据副本返回
    33         List<String> rs = new ArrayList<>(data);
    34         data.clear();
    35         hasData = false;
    36         notify();
    37         return rs;
    38     }
    39 }
    数据仓库
     1 public class Producer implements  Runnable {
     2     private DataRepository dataRepository;      //数据仓库
     3     public Producer(DataRepository dataRepository) {
     4         this.dataRepository = dataRepository;
     5     }
     6 
     7     public void run() {
     8         while (true) {
     9             try {
    10                 Thread.sleep(1000);
    11             } catch (InterruptedException e) {
    12                 e.printStackTrace();
    13             }
    14             List<String> temp = new ArrayList<>();
    15             temp.add("------------");
    16             temp.add("第一个数据");
    17             temp.add("第二个数据");
    18             temp.add("第三个数据");
    19             temp.add("第四个数据");
    20             temp.add("------------");
    21             try {
    22                 dataRepository.put(temp);
    23             } catch (InterruptedException e) {
    24                 e.printStackTrace();
    25             }
    26         }
    27     }
    28 }
    生产者
     1 public class Consumer implements Runnable {
     2     private DataRepository dataRepository;
     3 
     4     public Consumer(DataRepository dataRepository) {
     5         this.dataRepository = dataRepository;
     6     }
     7 
     8     public void run() {
     9         while (true) {
    10             try {
    11                 Thread.sleep(1000);
    12             } catch (InterruptedException e) {
    13                 e.printStackTrace();
    14             }
    15             try {
    16                 List<String> data=dataRepository.get();
    17                 if(data!=null&&!data.isEmpty()){
    18                     for (String temp :data){
    19                         System.out.println(temp);
    20                     }
    21                 }
    22             } catch (InterruptedException e) {
    23                 e.printStackTrace();
    24             }
    25         }
    26     }
    27 }
    消费者
    1 public class Client {
    2     public static void main(String[] args) throws InterruptedException {
    3    
    4         DataRepository dr=new DataRepository();
    5         new Thread(new Producer(dr)).start();   //启动生产者线程
    6         new Thread(new Consumer(dr)).start();   //启动消费者线程
    7     }
    8 }
    调用端

    后记:

      a). 多线程属于较基础的知识,我们首先需要了解其最基本的概念,才能在项目中游刃有余的应用;

      b).不管是什么语言,其所需要的理论支持均大同小异;

      c).回到最初的那个概念,在多线程中,能不需要线程互相通讯就尽量不要用,能不同步就尽量不要使用线程同步,能不使用多线程就尽量不要使用多线程,说得有些含糊,各位自己去参悟吧.

  • 相关阅读:
    Spring核心概念
    动态SQL
    SQL的映射文件
    初始MyBatis
    数据库SQL调优
    使用Spring Boot+MyBatis框架做查询操作
    SSM框架整合核心内容
    JavaScript基础
    MySQL的基本操作
    Java体系结构介绍
  • 原文地址:https://www.cnblogs.com/xie-zhonglai/p/java_mul_thread.html
Copyright © 2011-2022 走看看