*1:同步代码块解决线程安全问题
*同步代码块格式:
- synchronized(对象)
- //这里的对象相当于就是一把锁,多个线程必须是同一把锁。
- {
- (需要同步的代码);//让某个线程在执行的时候,别人不能执行。
- }
- 对象:
-
我们可以随便创建一个对象试试。
- 需要同步的代码是哪些呢?
-
把多条语句操作共享数据的代码的那部分给包起来 。
*同步的特点好处和弊端
-
特点
-
多个线程
-
解决问题的时候要注意:
-
多个线程使用的是同一个锁对象
*同步的好处
-
同步的出现解决了多线程的安全问题
*同步的弊端
-
当线程相对多时,因为每个线程都会去判断同步上的锁,
-
这是很耗费资源的,无形中会降低程序的运行效率
*2:同步方法的格式及所对象问题
- 同步方法就是把同步关键字加在方法上。
- 同步方法的锁对象是谁呢?this关键字。
*3:静态方法及锁对象问题
- 静态方法的锁对象是谁呢?
- 类的字节码文件对象(反射会讲)
- 例:
public class SynchronizedDemo {
public static void main(String[] args) {
//创建资源对象
SellTicket st=new SellTicket();
//创建线程对象
Thread t1=new Thread(st,“窗口1”);
Thread t2=new Thread(st,“窗口2”);
Thread t3=new Thread(st,“窗口3”);
//启动线程
t1.start();
t2.start();
t3.start();
}
}
class SellTicket implements Runnable{
private int tickets=100;
//定义同一把锁
private Object obj=new Object();
public void run() {
while(true) {
/**
* t1.t2.t3都能走到这里
* 假设t1抢到CPU的执行权,t1就要进来
* 假设t2抢到CPU的执行权,t2就要进来,发现门是关着的,进不去,就得等着
* 门(开,关)
*/
synchronized(obj) {
if(tickets>0) {
try {
Thread.sleep(100);//t1就睡眠了
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+“正在出售第”+(tickets–)+“张票”);
//窗口1正在出售第100百张票
}
}
//t1就出来了,然后就开门。(开)
}
}
}
*拓展:
*虽然我们可以理解同步代码块和同步方法的锁对象问题,但是我们并没有直接
*看到在哪里加上了锁,在哪里释放了锁,为了更清晰的表达如何加锁,如何释放锁:
*JDK5提供了一个新的锁对象Lock.
*Lock(接口)
-
void lock() 获取锁
-
void unlock() 释放锁
-
ReentrantLock是Lock的实现类
public class LockDemo {
public static void main(String[] args) {
//创建资源对象
SellTicket st=new SellTicket();
//创建线程对象
Thread t1=new Thread(st,“窗口1”);
Thread t2=new Thread(st,“窗口2”);
Thread t3=new Thread(st,“窗口3”);
//启动线程
t1.start();
t2.start();
t3.start();
}
}
class SellTicket implements Runnable{
private int tickets=100;
//定义锁对象
private Lock lock=new ReentrantLock();
public void run() {
while(true) {
try {
//加锁
lock.lock();
if(tickets>0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+“正在出售第”+(tickets–)+“张票”);
}
}finally//为了保证中间代码出现问题,也能释放锁
{
//释放锁
lock.unlock();
}
}
}
}
死锁:
- 同步的弊端
-
A:效率低
-
B:容易产生死锁
-
两个或两个以上的线程在争夺资源的过程中,出现相互等待的现象
- 举个模拟死锁小例子
-
中国人美国人吃饭案例.
-
正常情况下:
-
中国人:筷子两支
-
美国人:刀和叉
-
现在:
-
中国人:筷子一支,刀一把
-
美国人:筷子一支,叉一把
例:
public class DieDemo {
public static void main(String[] args) {
//创建两个线程对象,并标记
DieLock dl1=new DieLock(true);
DieLock dl2=new DieLock(false);
//启动线程
dl1.start();
dl2.start();
}
}
class MyLock{
//创建两把锁对象
public static final Object objA=new Object();
public static final Object objB=new Object();
}
class DieLock extends Thread{
private boolean flag;
public DieLock(boolean flag) {
this.flag=flag;
}
public void run() {
if(flag) {
synchronized(MyLock.objA) {
System.out.println(“if objA”);
synchronized(MyLock.objB) {
System.out.println(“if objB”);
}
}
}else {
synchronized(MyLock.objB) {
System.out.println(“else objB”);
synchronized(MyLock.objA) {
System.out.println(“else objA”);
}
}
}
}
}