同步机制:
解决多线程安全问题
同步代码块
格式:
synchronized (锁对象) {
需要同步的代码
}
(普通同步方法)
(静态同步方法)
格式:
修饰符 synchronized 返回值类型 方法名(参数列表){....}
同步方法,同步方法的锁对象是谁? this
同步方法,同步静态方法的锁对象是谁? 字节码文件对象, 类名.class
Lock锁: jdk1.5
void lock()获取锁。
死锁:
是指两个或者两个以上的线程在执行的过程中,因争夺资源(锁对象)产生的一种互相等待现象,下面是一段死锁的代码:
/*
等待:
感谢传智!
解决多线程安全问题
同步代码块
格式:
synchronized (锁对象) {
需要同步的代码
}
<span style="font-size:24px;">public void run() {
<span style="white-space:pre"> </span>int i = 1; </span>
<span style="font-size:24px;">
</span>
<span style="font-size:24px;"><span style="white-space:pre"> </span>while(i<100){</span>
<span style="font-size:24px;"><span style="white-space:pre"> </span></span>
<span style="font-size:24px;"> <span style="white-space:pre"> </span>//需要是同一把锁才能起到作用
<span style="white-space:pre"> </span>synchronized (obj) {
<span style="white-space:pre"> </span>//需要被同步的内容,也就是需要多线程并发访问的内容</span>
<span style="font-size:24px;"><span style="white-space:pre"> </span>System.out.println(i++);</span>
<span style="font-size:24px;"><span style="white-space:pre"> </span>}</span>
<span style="font-size:24px;"><span style="white-space:pre"> </span>}<span style="white-space:pre"> </span></span>
<span style="font-size:24px;">}</span>
同步方法
(普通同步方法)
(静态同步方法)
格式:
修饰符 synchronized 返回值类型 方法名(参数列表){....}
</pre><pre name="code" class="java">//需要被多线程并发访问的同步方法
public synchronized void method(){
<span style="white-space:pre"> </span>//方法内容<span style="font-family: Arial, Helvetica, sans-serif;"> </span>
}
<pre name="code" class="java">//需要被多线程并发访问的静态同步方法
public static synchronized void method(){
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>//方法内容
}
/*
<span style="white-space:pre"> </span>它们的区别在于,所对象不同。
<span style="white-space:pre"> </span>普通同步方法的锁对象是 tish
<span style="white-space:pre"> </span>而静态同步方法的锁对象是 字节码文件对象:
<span style="white-space:pre"> </span>类名.class
<span style="white-space:pre"> </span>那用谁好呢?
<span style="white-space:pre"> </span>它们的区别是:<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>静态与非静态,用谁就要看用静态还是不用静态
*/<span style="white-space:pre"> </span>
注意:
同步方法,同步方法的锁对象是谁? this
同步方法,同步静态方法的锁对象是谁? 字节码文件对象, 类名.class
Lock锁: jdk1.5
void lock()获取锁。
void unlock()释放锁。
//新锁的使用与老锁一样,但它需要手动的释放锁。
<span style="white-space:pre"> </span>int i=100;
<span style="white-space:pre"> </span>//创建锁对象
<span style="white-space:pre"> </span>Lock lock=new ReentrantLock();
public void run(){
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>while (true){
<span style="white-space:pre"> </span>//加锁
<span style="white-space:pre"> </span>lock.lock();
<span style="white-space:pre"> </span>//被同步的内容
if (0<i){
<span style="white-space:pre"> </span>System.out.println(--i);
}
<span style="white-space:pre"> </span>//释放锁
lock.unlock();
}
}
死锁:
是指两个或者两个以上的线程在执行的过程中,因争夺资源(锁对象)产生的一种互相等待现象,下面是一段死锁的代码:
public class ThreadList {
public static void main(String[] args) {
//创建两个多线程对象,并赋值
DieThread die = new DieThread("帅哥", true);
DieThread die1 = new DieThread("美女", false);
//启动多线程
die.start();
die1.start();
}
}
<pre name="code" class="html">public class DieThread extends Thread {
// 定义变量,用于判断被执行的代码
public boolean flag;
// 定义线程名称
public String name;
// 创建锁对象
public static Object obj = new Object();
public static Object obj1 = new Object();
// 用于赋值的构造方法
DieThread(String name, boolean flag) {
this.name = name;
this.flag = flag;
};
// 重写run方法
public void run() {
// 判断标签
if (flag) {
// 重复执行同步代码
while (true) {
// 锁1
synchronized (obj1) {
System.out.println(getName() + "obj----obj");
// 锁0
synchronized (obj) {
System.out.println(getName() + "obj1---obj1");
}
}
}
} else {
// 重复执行同步代码
while (true) {
// 锁0
synchronized (obj) {
System.out.println(getName() + "obj---obj");
// 锁1
synchronized (obj1) {
System.out.println(getName() + "obj1---obj1");
}
}
}
}
}
}
/*
<span style="white-space:pre"> </span>死锁是因为:
<span style="white-space:pre"> </span>线程一拿到了锁1,正在判断锁0.
<span style="white-space:pre"> </span>而线程二拿到了锁0,正在判断锁1.
<span style="white-space:pre"> </span>因为同一个锁只能进入一个对象,所以线程一进不去已经存在对象的锁0,线程二也同理。但它们都有各自的任务,那就是解开下一个锁,所以它们都不会释放锁。
*/
等待:
wait(): 让当前的线程等待,释放锁对象,让其他线程获取锁对象与CPU执行权,
等待着其他线程 调用 notify()\notifyAll()来 唤醒
notify()\notifyAll() : 可以唤醒当前锁对象上面的等待的线程
notify(): 随机唤醒锁对象上面的其中一个等待的线程对象
//多生产多消费问题,等待唤醒机制
class Resource
{
private String name;
private int count = 1;
//定义标记。
private boolean flag = false;
//1,提供设置的方法。
public synchronized void set(String name)
{
while(flag)
<span style="white-space:pre"> </span>/*睡眠方法会抛出<code>terruptedException</code>异常
<span style="white-space:pre"> </span> 如果在当前线程等待通知之前或者正在等待通知时
<span style="white-space:pre"> </span> ,任何线程中断了当前线程。在抛出此异常时,
<span style="white-space:pre"> </span> 当前线程的<em>中断状态</em> 被清除。
<span style="white-space:pre"> </span>*/
try{this.wait();}catch(InterruptedException e){}
//给成员变量赋值并加上编号。
this.name = name + count;
//编号自增。
count++;
//打印生产了哪个商品。
System.out.println(Thread.currentThread().getName()+"......生产者...."+this.name);
//将标记改为true。
flag = true;
//唤醒消费者。
this.notifyAll();
}
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>//消费方法
public synchronized void out(){
while(!flag)
try{this.wait();}catch(InterruptedException e){}
System.out.println(Thread.currentThread().getName()+"....消费者...."+this.name);
//将标记该为false。
flag = false;
//唤醒生产者。
this.notifyAll();
}
}
//2,描述生产者。
class Producer implements Runnable
{
private Resource r ;
// 生产者一初始化就要有资源,需要将资源传递到构造函数中。
Producer(Resource r)
{
this.r = r;
}
public void run()
{
while(true)
{
r.set("面包");
}
}
}
//3,描述消费者。
class Consumer implements Runnable
{
private Resource r ;
// 消费者一初始化就要有资源,需要将资源传递到构造函数中。
Consumer(Resource r)
{
this.r = r;
}
public void run()
{
while(true)
{
r.out();
}
}
}
class ThreadDemo10
{
public static void main(String[] args)
{
//1,创建资源对象。
Resource r = new Resource();
//2,创建线程任务。
Producer pro = new Producer(r);
Consumer con = new Consumer(r);
//3,创建线程。
Thread t1 = new Thread(pro);
Thread t2 = new Thread(pro);
Thread t3 = new Thread(con);
Thread t4 = new Thread(con);
t1.start();
t2.start();
t3.start();
t4.start();
}
}
感谢传智!