1.死锁以及避免死锁
线程同时含有多个对象的锁,那么当多个线程同时开启时,有可能造成死锁,过多的同步可能会造成相互不释放资源,从而相互等待,一般发生于同步中持有多个对象的锁
解决死锁:避免在一个代码块中同时持有多个对象的锁
static和final
1、final可以修饰:类变量、成员变量、局部变量、方法、类。
1.1、被final修饰的变量:必须直接赋值,并且不再允许在其他地方改值。
1.2、被final修饰的方法:不能被复写。
1.3、被final修饰的类:不能被继承。
2、static可以修饰:成员变量、方法。
2.1、被static修饰的成员变量:成员变量变为类变量,可以在所有的方法中访问。可以被多次重新赋值。
2.2、被static修饰的方法:在静态方法中可以直接调用。在非静态方法、静态方法中,都可以直接调用。不能被子类复写。
package cn.MulThread.java.mhz;
/**
* 死锁机制: 过多的同步可能会造成相互不释放资源,从而相互等待,一般发生于同步中持有多个对象的锁
* 解决死锁:避免在一个代码块中同时持有多个对象的锁
* 线程同时持有多个对象的锁,可能造成死锁
* @author MHZ
*
*/
public class DeadLock {
public static void main(String[] args) {
MakeUp g1 = new MakeUp(0,"zbz");
MakeUp g2 = new MakeUp(1,"zs");
g1.start();
g2.start();
}
}
//口红
class Lipstick{
}
//镜子
class Mirror{
}
//化妆
class MakeUp extends Thread{
//static可以修饰成员变量和成员方法,被static修饰的成员变量为类变量,可以在所有的方法中被访问,也可以重新赋值
//static修饰的 成员方法,在静态方法中可以直接调用,在非静态,静态中都可以直接调用,但是不能被子类复写
static Lipstick lipstick = new Lipstick(); //使用static修饰,属于类不属于对象,所以在不同的对象声明时属于同一块资源
static Mirror mirror = new Mirror();
//选择
int choice;
String girlname;
public MakeUp(int choice, String name) {
super();
this.choice = choice;
this.girlname = name;
}
@Override
public void run() {
// TODO Auto-generated method stub
makeup();
}
//相互持有对方的对象锁----->可能造成死锁
//解决方法:避免锁套锁
private void makeup()
{
if(this.choice==0) {
synchronized(lipstick) { //获得口红的锁
System.out.println(this.girlname + "涂口红");
// 1s后想拥有镜子
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
synchronized (mirror) { // 获得镜子的锁
System.out.println(this.girlname + "照镜子");
}
} else {
synchronized (mirror) { // 获得镜子的锁
System.out.println(this.girlname + "照镜子");
// 2s后想拥有口红
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
synchronized (lipstick) { // 获得口红的锁
System.out.println(this.girlname + "涂口红");
}
}
}
}
2.线程合作
生产者---缓冲区---消费者 有两种方式:管程法
同步方法
管程法:
package cn.MulThread.java.mhz;
/**
* 线程协作
* 生产者 --------- 缓冲区 --------- 消费者
* 协作模型:生产者-消费者实现方式一:管程法
* @author MHZ
*
*/
public class MyJavaMulThreadCooperation {
public static void main(String[] args) {
SynCotainer container = new SynCotainer();
Thread pro = new Productor(container);
Thread cus = new Custom(container);
pro.start();
cus.start();
}
}
//生产者
class Productor extends Thread{
SynCotainer container;
public Productor(SynCotainer container) {
super();
this.container = container;
}
@Override
public void run() {
//开始生产
for(int i=0;i<100;i++)
{
System.out.println("生产了---->"+i+"个数据");
this.container.push(new Data(i));
}
}
}
//消费者
class Custom extends Thread{
//开始消费
SynCotainer container;
//何时不能消费 当缓冲区内没有数据时不能消费
public Custom(SynCotainer container) {
super();
this.container = container;
}
@Override
public void run() {
//消费者消费
for(int i=0;i<100;i++)
{
System.out.println("消费--->"+container.pop().id+"个数据");
}
}
}
//缓冲区 需要操作数据的容器
class SynCotainer{
Data[] datas =new Data[10];
int num = 0; //计数器,指向当前需要存储的位置
//存储
public synchronized void push(Data d)
{
//容器存在空间,可以生产 如果容器满,则不能生产
if(num==datas.length)
{
try {
this.wait(); //线程阻塞,消费者通知生产解除阻塞
} catch (InterruptedException e) {
e.printStackTrace();
}
}
datas[num++]=d;
this.notify();
}
//拿走消费
public synchronized Data pop()
{
if(num == 0) {
try {
this.wait(); //此时线程阻塞,生产者通知消费解除阻塞
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
num--;
Data k = datas[num];
this.notify(); //存在空间,通知生产
return k;
}
}
//数据
class Data{
int id;
public Data(int id) {
this.id = id;
}
}
3.线程合作
生产者 - 消费者 模式,采用信号灯模式实现
同步方法
package cn.MulThread.java.mhz;
/**
* 线程合作:信号灯法 生产者 -消费者模式实现
* 借助标志位
*
* @author MHZ
*
*/
public class MyJavaMulThreadCooperation02 {
public static void main(String[] args) {
Tv tv = new Tv();
new Player(tv).start();
new Viewer(tv).start();
}
}
// 演员 观众 电视( 会变的资源,使用锁机制)
class Player extends Thread{
Tv tv;
public Player(Tv tv) {
super();
this.tv = tv;
}
@Override
public void run() {
for(int i=0;i<20;i++)
{
if(i%2==0) this.tv.play("奇葩说");
else this.tv.play("阿圆爱你哦");
}
}
}
class Viewer extends Thread{
Tv tv;
public Viewer(Tv tv) {
super();
this.tv = tv;
}
@Override
public void run() {
for(int i=0;i<20;i++)
{
this.tv.watch();
}
}
}
class Tv{
String voice;
boolean flag = true;
//True 表示演员表演 观众等待
//False 表示观众观看 演员等待
public synchronized void play(String voice)
{
//演员表演 观众等待
if(!flag)
{
try {
this.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
this.flag=!this.flag;
this.voice = voice;
System.out.println("表演了"+voice);
this.notify();
}
public synchronized void watch()
{
//观众观看 演员等待
if(flag)
{
try {
this.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.println("观看了------>"+this.voice);
this.flag=!this.flag;
this.notify();
}
}
4.多线程高级主题之定时调度
Timer和TimerTask Timer相当于一个线程,TimerTask自己实现了Runnable接口
package cn.MulThreadOthers.java.mhz;
import java.util.Timer;
import java.util.TimerTask;
/**
* 多线程高级主题之定时调度
* @author MHZ
*
*/
public class MyMulThreadJavaOthers {
public static void main(String[] args) {
Timer timer = new Timer(); //timer相当于一个线程,TimerTask自己实现了Runnable接口
//执行安排
timer.schedule(new MyTask(), 1000); //1s后调度
timer.schedule(new MyTask(), 10000,200); //10s后调度,每隔200ms调度一次 delay:延迟,指向第一次调度的时间
}
}
//继承抽象类
class MyTask extends TimerTask{
@Override
public void run() {
for(int i=0;i<10;i++)
System.out.println("easy easy");
System.out.println("end");
}
}
把上面的线程合作改写成一个定时调度的版本
package cn.MulThread.java.mhz;
import java.util.Timer;
import java.util.TimerTask;
/**
* 一个类只能被public或者默认权限访问
* 线程合作:信号灯法 生产者 -消费者模式实现
* TimerTask 实现了Runnable接口
* 借助标志位
*
* @author MHZ
*
*/
public class MyJavaMulThreadCooperation02 {
public static void main(String[] args) {
Tv tv = new Tv();
MakeUp1 M = new MakeUp1(tv);
Timer timer = new Timer(); //timer相当于一个线程,TimerTask自己实现了Runnable接口
timer.schedule(M,10000, 5000);
}
}
class MakeUp1 extends TimerTask{ //实现了Runnable接口
Tv tv;
public MakeUp1(Tv tv)
{
this.tv = tv;
}
//重写run方法
@Override
public void run()
{
new Thread(new Player(this.tv)).start();
new Thread(new Viewer(this.tv)).start();
try {
Thread.sleep(1000);
System.out.println("----------------------------------------------------------------------");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
// 演员 观众 电视( 会变的资源,使用锁机制)
class Player extends TimerTask{
Tv tv;
public Player(Tv tv) {
super();
this.tv = tv;
}
@Override
public void run() {
for(int i=0;i<20;i++)
{
if(i%2==0) this.tv.play("奇葩说");
else this.tv.play("阿圆爱你哦");
}
}
}
class Viewer extends TimerTask{
Tv tv;
public Viewer(Tv tv) {
super();
this.tv = tv;
}
@Override
public void run() {
for(int i=0;i<20;i++)
{
this.tv.watch();
}
}
}
class Tv{
String voice;
boolean flag = true;
//True 表示演员表演 观众等待
//False 表示观众观看 演员等待
public synchronized void play(String voice)
{
//演员表演 观众等待
if(!flag)
{
try {
this.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
this.flag=!this.flag;
this.voice = voice;
System.out.println("表演了"+voice);
this.notify();
}
public synchronized void watch()
{
//观众观看 演员等待
if(flag)
{
try {
this.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.println("观看了------>"+this.voice);
this.flag=!this.flag;
this.notify();
}
}
5.指令重排 happenbefore
1.指令重排是为了减少因内存速度远慢于cpu运行速度所带来的cpu空置的影响,是为了提高效率
2.下面说一下指令执行的过程:首先获取指令,接着解码翻译,从寄存器中取值,随后做出操作,最后将结果写回到寄存器,将结果写回到寄存器的执行过程中,可能执行速度过慢,这时会先执行下一条指令
3.happenbefore是编译器或运行环境为了优化程序性能而采取的对指令进行排序执行的一种手段,当前后指令之间的数据之间不存在依赖关系时,可能会发生指令重排