layout: post title: "java之多线程" subtitle: " "多线程的基础知识"" date: 2018-10-07 06:00:00 author: "青乡" header-img: "img/post-bg-2015.jpg" catalog: true tags: - multi thread
什么是死锁?死锁是怎么发生的?
1.2个线程
2.2个锁对象
每个线程各自拥有一个锁对象,同时,每个线程还要去获取另外一个锁对象,但是这个锁对象已经被对方线程占有。
写一个死锁的代码?
锁对象1
锁对象2
方法1(){
synchronized(锁对象1){
synchronized(锁对象2){
...
}
}
}
方法2(){
synchronized(锁对象2){
synchronized(锁对象1){
...
}
}
}
复制代码
为什么会出现数据不同步的情况?
1.多线程
2.对象堆
主要是从内存的角度看,对象堆里的数据,多线程共享。
代码 //多线程访问对象堆里的数据
package gzh.test.multiThread;
/**
* 启动程序
*
* ---调试技巧---
* 如何才能不按线程顺序输出?
* 调试的时候,在线程1打断点,就会先执行线程2的任务。
* @author gongzhihao
*
*/
public class MultiThreadTest {
static Data d = new Data(); //对象堆里的数据,线程共享
public static void main(String[] args) {
//初始数据
System.out.println("a=" + d.a + ", flag=" + d.flag);
System.out.println();
//多线程访问数据
// for (int i = 0; i < 10; i++) {
// Thread t1 = new Thread(new TaskThread1());
// t1.start();
// }
Thread t1 = new Thread(new TaskThread1());
t1.start();
Thread t2 = new Thread(new TaskThread2());
t2.start();
}
}
复制代码
package gzh.test.multiThread;
/**
* 任务线程
* @author gongzhihao
*
*/
public class TaskThread1 implements Runnable{
public void run() {
System.out.println("current thread: " + Thread.currentThread() + ", MultiThreadTest.d: " + MultiThreadTest.d);
MultiThreadTest.d.writer();
}
}
复制代码
package gzh.test.multiThread;
/**
* 任务线程
* @author gongzhihao
*
*/
public class TaskThread2 implements Runnable{
public void run() {
System.out.println("current thread: " + Thread.currentThread() + ", MultiThreadTest.d: " + MultiThreadTest.d);
MultiThreadTest.d.reader();
}
}
复制代码
package gzh.test.multiThread;
/**
* 数据
* @author gongzhihao
*
*/
class Data {
int a = 0;
boolean flag = false;
public synchronized void writer() {
a = 1;
System.out.println("a=" + a);
flag = true;
System.out.println("flag=" + flag);
}
public synchronized void reader() {
System.out.println("flag=" + flag);
if (flag) {
System.out.println("flag=" + flag);
int i = a;
System.out.println("i=" + i);
}
}
}
复制代码
输出结果
a=0, flag=false
current thread: Thread[Thread-0,5,main], MultiThreadTest.d: [email protected] //看共享数据id,可以看出来是同一个对象67565b6a
current thread: Thread[Thread-1,5,main], MultiThreadTest.d: [email protected]
flag=false
a=1
flag=true
复制代码
为什么要同步?
确保同一时刻,只有一个线程写数据。
进程和线程
进程
与线程的关系 包含多个线程。
如何通信?
不同进程是不同的地址空间。即不同进程里的数据互相不能访问。
那不同进程如何通信? 每个进程是一个应用程序,ip+端口 唯一的确定一个应用程序,所以不同程序/进程的通信底层都是通过ip+端口,先定位到哪一台机器的哪一个程序,然后再调用该程序提供的服务。例如,分布式服务之间的通信,是调用别的机器的远程服务。
进程怎么通信?
1.套接字
2.消息中间件
3.远程服务
2个不同的程序,可以实现数据互通!
线程
与进程的关系 属于进程。 一个进程一般是一个应用程序,一个应用程序要完成多个任务,就会出现多线程。这是多线程最大的作用。
如何通信?
共用同一个进程空间(即内存),所以会导致数据不一致。这是最大的问题。
如何解决数据不一致的问题?
基本上所有的多线程和同步技术都是在解决这个问题。
线程的状态
1.新建
new Thread();
2.在运行
Thread.start();
3.睡眠/阻塞
.sleep();
IO阻塞; //本地数据访问、网络数据访问,都会出现访问数据阻塞,例如,数据量太大,网络不好。
4.再次运行
睡醒了;
IO完毕。
5.结束/死亡
代码运行完毕。
怎么同步
有2种方法,
1.基础
即常用方法。一般使用同步关键字,同步方法或代码块。
2.提高
jdk 线程池。
jdk 高级并发类。
以上都是属于jdk并发包的内容。
怎么使用?
底层原理?
java并发包
线程池
并发集合和映射
显式锁
优点
1.显式锁
2.可以控制同步粒度
还有优点
1.中断
2.超时
并发原子
happen-before
代码是有先后执行顺序的。这个先后执行顺序就是所谓的happen-before规则。
指令重排序
就是多线程的代码没有先后顺序,完全随机。
线程组ThreadGroup
作用是方便统一管理线程,以及线程的各个特性。
每个线程都属于一个线程组,还有一个父线程组。
参考
1.官方文档 docs.oracle.com/javase/tuto…
2.1)讲并发的有一本书 很好 看那一本书就够
2)还有一本是jdk 并发包 作者写的
3.再结合google 和 *