JAVA基础----同步锁

来源:互联网 发布:win8垃圾清理软件 编辑:程序博客网 时间:2024/05/17 04:13
同步机制:
解决多线程安全问题
   
同步代码块
格式:
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) {// 锁1synchronized (obj1) {System.out.println(getName() + "obj----obj");// 锁0synchronized (obj) {System.out.println(getName() + "obj1---obj1");}}}} else {// 重复执行同步代码while (true) {// 锁0synchronized (obj) {System.out.println(getName() + "obj---obj");// 锁1synchronized (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(): 随机唤醒锁对象上面的其中一个等待的线程对象


notifyAll(): 唤醒锁对象上面的所有等待的线程对象


//多生产多消费问题,等待唤醒机制
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();}}

感谢传智!

0 0
原创粉丝点击