本文简要介绍在 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). 演示线程创建与销毁,及线程安全与同步

 public class ThreadTest implements Runnable {
     private boolean stop;                   //是否需要停止运行
     private int tiketCount = 100000;        //总票数
     private boolean lockTypeIsMethod = true; //是否是提供方法锁定还是代码块

     public boolean isStop() {
         return stop;
     }
     public void setStop(boolean stop) {
         this.stop = stop;
     }

     public boolean isLockTypeMethod() {
         return lockTypeIsMethod;
     }
     public void setLockTypeIsMethod(boolean lockTypeIsMethod) {
         this.lockTypeIsMethod = lockTypeIsMethod;
     }

     @Override
     public void run() {
         while (tiketCount > 0 && !stop) {
             try {
                 Thread.sleep(50);    //延时1秒,方便演示
             } catch (InterruptedException e) {
                 e.printStackTrace();
             }

             //如果是通过锁定方法
             if (lockTypeIsMethod) {
                 sale();
             } else {
                 synchronized (this) {
                     if (tiketCount > 0 && !stop) {
                         System.out.println("使用代码块锁定:threadId="
                                 + Thread.currentThread().getName() + ",ticketNO:" + tiketCount--);
                     }
                 }
             }
         }
     }

     public synchronized void sale() {
         if (tiketCount > 0 && !stop) {
             System.out.println("使用方法锁定:threadId="
                     + Thread.currentThread().getName() + ",ticketNO:" + tiketCount--);
         }
     }
 }

线程定义类

 public static void main(String[] args) throws InterruptedException {
     ThreadTest threadTest = new ThreadTest();   //共享变量ThreadTest
     //启用四个线程
     new Thread(threadTest).start();
     new Thread(threadTest).start();
     new Thread(threadTest).start();
     new Thread(threadTest).start();
     //模拟设置共享变量,
     // 1.交替使用方法体和代码块来进行线程同步实验
     // 2.模拟线程停止
     for (int i = 0; i < 100; i++) {
         Thread.sleep(1000);
         threadTest.setLockTypeIsMethod(i % 2 == 0);
         if (i == 50) {
             threadTest.setStop(true);
         }
     }
 }

调用端

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

 //数据仓库
 public class DataRepository {
     private List<String> data = new ArrayList<>();
     private boolean hasData;

     public boolean HasData() {
         return hasData;
     }

     public void setHasData(boolean hasData) {
         this.hasData = hasData;
     }

     //放入数据
     public synchronized void put(List<String> data) throws InterruptedException {
         //生产者放入数据的时候,如果还有数据则等待.
         if (hasData) {
             wait();
         }
         this.data = data;
         hasData = true;
         //放入完毕后通知消费者
         notify();
     }

     //读取数据
     public synchronized List<String> get() throws InterruptedException {
         //没有数据则等待
         if (!hasData) {
             wait();
         }
         //获取数据副本返回
         List<String> rs = new ArrayList<>(data);
         data.clear();
         hasData = false;
         notify();
         return rs;
     }
 }

数据仓库

 public class Producer implements  Runnable {
     private DataRepository dataRepository;      //数据仓库
     public Producer(DataRepository dataRepository) {
         this.dataRepository = dataRepository;
     }

     public void run() {
         while (true) {
             try {
                 Thread.sleep(1000);
             } catch (InterruptedException e) {
                 e.printStackTrace();
             }
             List<String> temp = new ArrayList<>();
             temp.add("------------");
             temp.add("第一个数据");
             temp.add("第二个数据");
             temp.add("第三个数据");
             temp.add("第四个数据");
             temp.add("------------");
             try {
                 dataRepository.put(temp);
             } catch (InterruptedException e) {
                 e.printStackTrace();
             }
         }
     }
 }

生产者

 public class Consumer implements Runnable {
     private DataRepository dataRepository;

     public Consumer(DataRepository dataRepository) {
         this.dataRepository = dataRepository;
     }

     public void run() {
         while (true) {
             try {
                 Thread.sleep(1000);
             } catch (InterruptedException e) {
                 e.printStackTrace();
             }
             try {
                 List<String> data=dataRepository.get();
                 if(data!=null&&!data.isEmpty()){
                     for (String temp :data){
                         System.out.println(temp);
                     }
                 }
             } catch (InterruptedException e) {
                 e.printStackTrace();
             }
         }
     }
 }

消费者

 public class Client {
     public static void main(String[] args) throws InterruptedException {

         DataRepository dr=new DataRepository();
         new Thread(new Producer(dr)).start();   //启动生产者线程
         new Thread(new Consumer(dr)).start();   //启动消费者线程
     }
 }

调用端

后记:

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

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

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

Java中线程总结的更多相关文章

  1. java中线程分两种,守护线程和用户线程。

    java中线程分为两种类型:用户线程和守护线程. 通过Thread.setDaemon(false)设置为用户线程: 通过Thread.setDaemon(true)设置为守护线程. 如果不设置次属性 ...

  2. java中线程机制

    java中线程机制,一开始我们都用的单线程.现在接触到多线程了. 多线性首先要解决的问题是:创建线程,怎么创建线程的问题: 1.线程的创建: 四种常用的实现方法 1.继承Thread. Thread是 ...

  3. Java中线程的使用 (2)-多线程、线程优先级、线程睡眠、让步、阻塞

    Java中线程的使用 (2)-多线程.线程优先级.线程睡眠.让步.阻塞 (一)多线程使用方法 说明:创建每个新的线程,一定要记得启动每个新的线程(调用.start()方法) class Xc3 ext ...

  4. Java中线程的实现:

    Java中线程的实现: 一.线程简介: 实现的两种方式为: 1.Thread类 2.Runnable接口 都在java.lang中 都有共通的方法:public void run() 二.线程常用方法 ...

  5. JAVA中线程同步方法

    JAVA中线程同步方法 1  wait方法:         该方法属于Object的方法,wait方法的作用是使得当前调用wait方法所在部分(代码块)的线程停止执行,并释放当前获得的调用wait所 ...

  6. 多线程(三) java中线程的简单使用

    java中,启动线程通常是通过Thread或其子类通过调用start()方法启动. 常见使用线程有两种:实现Runnable接口和继承Thread.而继承Thread亦或使用TimerTask其底层依 ...

  7. Java中线程池,你真的会用吗?

    在<深入源码分析Java线程池的实现原理>这篇文章中,我们介绍过了Java中线程池的常见用法以及基本原理. 在文中有这样一段描述: 可以通过Executors静态工厂构建线程池,但一般不建 ...

  8. Java中线程同步的理解 - 其实应该叫做Java线程排队

    Java中线程同步的理解 我们可以在计算机上运行各种计算机软件程序.每一个运行的程序可能包括多个独立运行的线程(Thread). 线程(Thread)是一份独立运行的程序,有自己专用的运行栈.线程有可 ...

  9. 沉淀再出发:java中线程池解析

    沉淀再出发:java中线程池解析 一.前言 在多线程执行的环境之中,如果线程执行的时间短但是启动的线程又非常多,线程运转的时间基本上浪费在了创建和销毁上面,因此有没有一种方式能够让一个线程执行完自己的 ...

  10. Java中线程和线程池

    Java中开启多线程的三种方式 1.通过继承Thread实现 public class ThreadDemo extends Thread{ public void run(){ System.out ...

随机推荐

  1. char , unsigned char 和 signed char 区别

    ANSI C 提供了3种字符类型,分别是char.signed char.unsigned char.char相当于signed char或者unsigned char,但是这取决于编译器!这三种字符 ...

  2. salesforce 零基础学习(七十)使用jquery table实现树形结构模式

    项目中UI需要用到树形结构显示内容,后来尽管不需要做了,不过还是自己做着玩玩,mark一下,免得以后项目中用到. 实现树形结构在此使用的是jquery的dynatree.js.关于dynatree的使 ...

  3. NDK 线程同步

    使用场景 对底层代码进行 HOOK, 不可避免的要考虑多线程同步问题, 当然也可以写个类似 java 的线程本地变量来隔离内存空间. 死锁分析 恩, 道理其实大家都懂的, 毕竟大学就学了操作系统,理论 ...

  4. Object类型知识总结,你掌握了多少?

      Object类型    ECMAScript中的对象其实就是一组数据和功能的集合.对象可以通过执行new操作符后跟要创建的对象类型的名称来创建.而创建Object类型的实例并为其添加属性和(或)方 ...

  5. Android启动篇 — init原理(一)

    ========================================================          ================================== ...

  6. 少年,是时候换种更优雅的方式部署你的php代码了

    让我们来回忆下上次你是怎么发布你的代码的: 1. 先把线上的代码用ftp备份下来 2. 上传修改了的文件 3. 测试一下功能是否正常 4. 网站500了,赶紧用备份替换回去 5. 替换错了/替换漏了 ...

  7. jsp实现仿QQ空间新建多个相册名称,向相册中添加照片

    工具:Eclipse,Oracle,smartupload.jar:语言:jsp,Java:数据存储:Oracle. 实现功能介绍: 主要是新建相册,可以建多个相册,在相册中添加多张照片,删除照片,删 ...

  8. python基本数据类型——tuple

    一.元组的创建与转换: ages = (11, 22, 33, 44, 55) ages = tuple((11, 22, 33, 44, 55))ages = tuple([]) # 字符串.列表. ...

  9. 用NodeJS创建一个聊天服务器

    Node 是专注于创建网络应用的,网络应用就需要许多I/O(输入/输出)操作.让我们用Node实现有多么简单,并且还能轻松扩展. 创建一个TCP服务器 var net = require('net') ...

  10. APP反编译第一课《如何找到核心代码》

    相信很多人都应该会去接触APP反编译,本小七给大家带来入门级别套路,自己也在慢慢摸索学习,一起成长吧.第一步,反编译需要的工具有:一.java环境,其实这里你只要安装了burp就不用管这个的二.apk ...