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). 演示线程创建与销毁,及线程安全与同步
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中线程总结的更多相关文章
- java中线程分两种,守护线程和用户线程。
java中线程分为两种类型:用户线程和守护线程. 通过Thread.setDaemon(false)设置为用户线程: 通过Thread.setDaemon(true)设置为守护线程. 如果不设置次属性 ...
- java中线程机制
java中线程机制,一开始我们都用的单线程.现在接触到多线程了. 多线性首先要解决的问题是:创建线程,怎么创建线程的问题: 1.线程的创建: 四种常用的实现方法 1.继承Thread. Thread是 ...
- Java中线程的使用 (2)-多线程、线程优先级、线程睡眠、让步、阻塞
Java中线程的使用 (2)-多线程.线程优先级.线程睡眠.让步.阻塞 (一)多线程使用方法 说明:创建每个新的线程,一定要记得启动每个新的线程(调用.start()方法) class Xc3 ext ...
- Java中线程的实现:
Java中线程的实现: 一.线程简介: 实现的两种方式为: 1.Thread类 2.Runnable接口 都在java.lang中 都有共通的方法:public void run() 二.线程常用方法 ...
- JAVA中线程同步方法
JAVA中线程同步方法 1 wait方法: 该方法属于Object的方法,wait方法的作用是使得当前调用wait方法所在部分(代码块)的线程停止执行,并释放当前获得的调用wait所 ...
- 多线程(三) java中线程的简单使用
java中,启动线程通常是通过Thread或其子类通过调用start()方法启动. 常见使用线程有两种:实现Runnable接口和继承Thread.而继承Thread亦或使用TimerTask其底层依 ...
- Java中线程池,你真的会用吗?
在<深入源码分析Java线程池的实现原理>这篇文章中,我们介绍过了Java中线程池的常见用法以及基本原理. 在文中有这样一段描述: 可以通过Executors静态工厂构建线程池,但一般不建 ...
- Java中线程同步的理解 - 其实应该叫做Java线程排队
Java中线程同步的理解 我们可以在计算机上运行各种计算机软件程序.每一个运行的程序可能包括多个独立运行的线程(Thread). 线程(Thread)是一份独立运行的程序,有自己专用的运行栈.线程有可 ...
- 沉淀再出发:java中线程池解析
沉淀再出发:java中线程池解析 一.前言 在多线程执行的环境之中,如果线程执行的时间短但是启动的线程又非常多,线程运转的时间基本上浪费在了创建和销毁上面,因此有没有一种方式能够让一个线程执行完自己的 ...
- Java中线程和线程池
Java中开启多线程的三种方式 1.通过继承Thread实现 public class ThreadDemo extends Thread{ public void run(){ System.out ...
随机推荐
- HTML5技术实现Web图形图像处理——WebPhotoshop精简版
WebPhotoshop精简版是利用HTML5技术在Web上实现对图形图像的处理,构建易维护.易共享.易于拓展.实时性的Web图形图像处理平台. 精简版功能包括:图形绘制.图像处理.图像操作.完整版包 ...
- 使用swagger实现web api在线接口文档
一.前言 通常我们的项目会包含许多对外的接口,这些接口都需要文档化,标准的接口描述文档需要描述接口的地址.参数.返回值.备注等等:像我们以前的做法是写在word/excel,通常是按模块划分,例如一个 ...
- shell脚本基本知识点
Shell 是一个用C语言编写的程序,它是用户使用Linux的桥梁.用户通过这个界面访问Linux操作系统内核的服务.Shell既是一种命令语言,又是一种程序设计语言. 1.Shell 环境 Shel ...
- http协议的八种请求类型
GET:向特定的资源发出请求. POST:向指定资源提交数据进行处理请求(例如提交表单或者上传文件).数据被包含在请求体中.POST请求可能会导致新的资源的创建和/或已有资源的修改. OPTIONS: ...
- Unity 类似FingerGestures 的相机跟随功能
本文原创,转载请注明出处:http://www.cnblogs.com/AdvancePikachu/p/6555188.html 最近在做一款VR项目,有一个查看功能,分为自由查看和跟随查看. 自由 ...
- 关于REST的浅显了解
REST 是一种软件架构风格 1.定义 REST即表述性状态传递(Representational State Transfer) 是一组架构约束条件和原则.是设计风格而不是标准. 满足这些约束条件和 ...
- Linux 系统管理04--账号管理
Linux系统管理04--账号管理 一.用户账号管理 1.用户账号概述 (1)用户账号的常见分类: 1>超级用户:root uid=0 gid=0 权限最大. 2>普通用户:uid> ...
- Amazon Alexa登录授权(Android)
访问Alexa的API,必须要携带AccessToken,也就是必须要登录授权,本文主要记录Amazon Alexa在Android平台上的登录授权过程. 一.在亚马逊开发者平台注册应用 进入亚马逊开 ...
- [进程管理] 理解 Linux 的处理器负载均值
原文链接: http://blog.scoutapp.com/articles/2009/07/31/understanding-load-averages http://www.gracecode. ...
- 2017云计算开源峰会 你是想听Linux谈开源还是想听OpenStack谈开源?
2017年,善于把握机遇的企业们不是正在开源,就是走在去开源的路上-- 开源是不是就意味着免费? 开源企业就是要当"活雷锋"? 开源项目究竟如何运作?如何参与开源社区? 如何获得最 ...