java 线程安全问题的解决办法 和死锁
2018-03-08 本文已影响0人
发光驴子
线程安全问题的解决办法
线程 安全问题的解决方案:sun提供了线程同步机制让我们解决这类问题的。
java线程同步机制的方式:
方式一:同步代码块
同步代码块的格式:
synchronized(锁对象){
需要被同步的代码...
}
同步代码块要注意事项:
1. 任意的一个对象都可以做为锁对象。
2. 在同步代码块中调用了sleep方法并不是释放锁对象的。
3. 只有真正存在线程安全问题的时候才使用同步代码块,否则会降低效率的。
4. 多线程操作的锁 对象必须 是唯一共享 的。否则无效。
class SaleTicket extends Thread{
static int num = 50;//票数 非静态的成员变量,非静态的成员变量数据是在每个对象中都会维护一份数据的。
static Object o = new Object();
public SaleTicket(String name) {
super(name);
}
@Override
public void run() {
while(true){
//同步代码块
synchronized ("锁") {//任意的一个对象都可以做为锁对象。对象为Static,但String特殊,因为字符串就是在字符串常量池中。
if(num>0){
System.out.println(Thread.currentThread().getName()+"售出了第"+num+"号票");
try {
Thread.sleep(100);//在同步代码块中调用了sleep方法并不是释放锁对象的。
} catch (InterruptedException e) {
e.printStackTrace();
}
num--;
}else{
System.out.println("售罄了..");
break;
}
}
}
}
}
public class Thread_02 {
public static void main(String[] args) {
String s =new String("abc");
String str1 = "abc";
System.out.println(str1 ==s);
//创建三个线程对象,模拟三个窗口
SaleTicket thread1 = new SaleTicket("窗口1");
SaleTicket thread2 = new SaleTicket("窗口2");
SaleTicket thread3 = new SaleTicket("窗口3");
//开启线程售票
thread1.start();
thread2.start();
thread3.start();
}
}
方式二:同步函数
同步函数就是使用synchronized修饰一个函数。
同步函数要注意的事项 :
1. 如果是一个非静态的同步函数的锁 对象是this对象(ps:这样会存在锁不住的情况,因为俩个对象调用同一个文件,就会出现俩个锁),如果是静态的同步函数的锁 对象是当前函数所属的类的字节码文件(class对象)。
2. 同步函数的锁对象是固定的,不能由你来指定 的。
推荐使用: 同步代码块。
原因:
1. 同步代码块的锁对象可以由我们随意指定,方便控制。同步函数的锁对象是固定 的,不能由我们来指定。
2. 同步代码块可以很方便控制需要被同步代码的范围,同步函数必须是整个函数 的所有代码都被同步了。
class BankThread extends Thread{
static int count = 5000;
public BankThread(String name){
super(name);
}
@Override //
public void run() {
getMoney();//这样也锁定住,但是会造成只能一个人取完全部的钱,因为只有循环结束,才会释放锁
}
//静态的函数---->函数所属 的类的字节码文件对象--->BankThread.class 唯一的。
public static synchronized void getMoney(){
while(true){
if(count>0){
System.out.println(Thread.currentThread().getName()+"取走了1000块,还剩余"+(count-1000)+"元");
count= count - 1000;
}else{
System.out.println("取光了...");
break;
}
}
}
}
public class Demo1 {
public static void main(String[] args) {
//创建两个线程对象
BankThread thread1 = new BankThread("老公");
BankThread thread2 = new BankThread("老婆");
//调用start方法开启线程取钱
thread1.start();
thread2.start();
}
}
出现线程安全问题的根本原因:
1. 存在两个或者两个以上 的线程对象,而且线程之间共享着一个资源。
2. 有多个语句操作了共享资源。
线程的死锁
/*
* java 中同步机制解决了线程安全问题,但是同时引发死锁现象
*
* 死锁现象:就是 俩个或者俩个以上线程,共同调用俩个或者以上的资源,发生共同等待的状态
*
* 死锁现象的出现的根本原因:
* 1.存在俩个或者俩个以上的线程
* 2.存在俩个或者俩个以上的共享资源
*
* 死锁现象的解决方案:没有方案,只能尽量避免发生而已
*/
class DeadLock extends Thread{
public DeadLock(String name){
super(name);
}
public void run(){
if("张三".equals(Thread.currentThread().getName())){
synchronized ("遥控器") {
System.out.println("张三拿到了遥控器,准备去拿电池!!");
synchronized ("电池") {
System.out.println("张三拿到了遥控器和电池,开始吹空调");
}
}
}else if("李四".equals(this.getName())){
synchronized ("电池") {
System.out.println("李四拿到了电池,准备去那遥控器");
synchronized ("遥控器") {
System.out.println("李四拿到了遥控器和电池,开始吹空调");
}
}
}
}
}
public class Thread_04 {
public static void main(String[] args) {
DeadLock l1=new DeadLock("张三");
DeadLock l2=new DeadLock("李四");
l1.start();
l2.start();
}
}