线程的同步和死锁

来源:互联网 发布:redis 加载缓存数据库 编辑:程序博客网 时间:2024/05/18 01:58

同步与死锁

需要了解: 什么情况下需要同步;
实现数据共享的时候
同步怎么实现
同步代码块或者同步方法解决
实现同步了有什么弊端
性能和效率会降低

publicclass MyThread implements Runnable {
privateint updateImage = 5;
@Override
publicvoid run() {
while(updateImage>0){
try {
Thread.sleep(400);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(“剩余:”+updateImage–+”图片没下载”);
}
}

}

publicclass SyncDemo1 {
publicstaticvoid main(String[] args) {
MyThread mt = new MyThread();//定义Runnable接口对象
Thread t1 = new Thread(mt);//转化成Thread类对象
Thread t2 = new Thread(mt);
Thread t3 = new Thread(mt);
t1.start();
t2.start();
t3.start();
}
}

这里写图片描述
下载5张图片,最后出来了0,-1张图片,原因是程序加了延迟操作,在图片没下载完的时候,另外的操作器以及进入while循环中,这就造成三个下载器都在while循环中,一次下载三张图片。
上面实现的其实就是数据共享的代码,但是出现了数据错乱,为了解决这样问题,可以使用同步代码块或者同步方法解决,
复习代码块
普通代码块:定义在方法里面,方法调用多少次运行多少次
构造块:定义在类里面,方法外面,优先构造方法执行,实例对象多少次就运行多少次。
静态代码块:使用static关键字,在类里面,方法外面,优先构造块执行,在类加载的时候运行一次
同步代码块:使用synchronized关键字声明的代码块
Synchronized(同步对象){
同步的代码
}

publicclassThreadDemo02{
publicstaticvoidmain(String[]args){
MyRunnable1mt=newMyRunnable1();//定义Runnable接口对象
Threadt1=newThread(mt);//转化成Thread类对象
Threadt2=newThread(mt);
Threadt3=newThread(mt);
t1.start();
t2.start();
t3.start();
}
}
classMyRunnable1implements Runnable{
privateint updateImage=5;
@Override
publicvoidrun(){//使用同步代码块加同步 套接字(不管哪个线程方法 套接字都是同一个)
//this 只实例化了一遍 所以这个对象不管你使用多少个线程访问都是同一个对象
//MyRunnable1.class
longoldtime=System.currentTimeMillis();
synchronized(this){
while(updateImage>0){
try{
Thread.sleep(400);//模拟图片下载
}catch(InterruptedExceptione){
e.printStackTrace();
}
System.out.println(“剩余:”+updateImage–+”图片没下载”);
}
}
System.out.println(System.currentTimeMillis()-oldtime);
}
}
从运行结果得知,加入同步操作之后,不会产生0和负数,测试得知加了同步代码的程序效率会明显降低很多。
结论:同步之后,执行下载五张图片的时间加长了。
同步方法:
Public synchronized 方法的返回值 方法名称(参数列表){}

publicclassThreadDemo02{
publicstaticvoidmain(String[]args){
MyRunnable3mt=newMyRunnable3();// 定义Runnable接口对象
Threadt1=newThread(mt,”a”);// 转化成Thread类对象
Threadt2=newThread(mt,”b”);
Threadt3=newThread(mt,”c”);
t1.start();
t2.start();
t3.start();
}
}

classMyRunnable1implements Runnable {
privateintupdateImage=5;

@Override
publicvoidrun(){// 使用同步代码块加同步套接字(不管哪个线程方法套接字都是同一个)
// this 只实例化了一遍所以这个对象不管你使用多少个线程访问都是同一个对象
// MyRunnable1.class
longoldtime=System.currentTimeMillis();
synchronized(this){
while(updateImage>0){
try{
Thread.sleep(400);// 模拟图片下载
}catch(InterruptedExceptione){
e.printStackTrace();
}
System.out.println(“剩余:”+updateImage–+”图片没下载”);
}
}
System.out.println(System.currentTimeMillis()-oldtime);
}
}

classMyRunnable3implements Runnable {
privateintupdateImage=5;

@Override
publicvoidrun(){// 使用同步代码块加同步套接字(不管哪个线程方法套接字都是同一个)
// this 只实例化了一遍所以这个对象不管你使用多少个线程访问都是同一个对象
// MyRunnable1.class
longoldtime=System.currentTimeMillis();
while(updateImage>0){
synchronized(this){
if(updateImage>0){
try{
Thread.sleep(400);// 模拟图片下载
}catch(InterruptedExceptione){
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+”剩余:”+updateImage–+”图片没下载”);
}
}
}
System.out.println(System.currentTimeMillis()-oldtime);
}
}
结论看出结果是一样的,所以使用同步代码块和同步方法结果是一样的。
单例,如果多线程访问单例模式,就会可能出现多个对象,达不到单例的目的。

0 0