------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------
多线程二
一、线程安全问题
线程安全问题出现的原因?
1、有多个线程存在
2、多个线程操作同一个资源空间
3、操作资源的语句有多句
二、线程安全问题的解决方案
通过同步可以解决线程安全问题。
三、线程同步的方法
1、同步代码块
2、同步函数
3、Lock锁
四、代码练习
1、同步代码块的练习
package it.heima.thread;
public class SycronizedDemo {
public static void main(String[] args) {
Student student = new Student();
Thread thread = new Thread(student, "张三");
Thread thread2 = new Thread(student, "李四");
thread.start();
thread2.start();
}
}
class Student implements Runnable {
Object obj=new Object();
@Override
public void run() {
while (apple > 1) {
synchronized (obj) {<span style="white-space:pre"> </span>//同一个锁对下昂
try {
Thread.sleep(10);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "吃了第" + apple-- + "个苹果");
}
}
}
int apple;<span style="white-space:pre"> </span>
public Student() {
apple = 100;
}
}
通过sycronized关键字将要同步的代码括起来,并通过锁对象锁住代码块。
锁对象可以是任意对象,但是要同一把锁才能锁住多个线程。sycronized(new Object())有多个"锁",所以锁不住。
2、同步函数
同步函数分为2个部分:静态同步函数与非静态同步函数
同步函数的锁对象是固定的,不能修改,非静态同步函数的锁对象是this,静态同步函数的锁对象是class对象。
代码测试:
package it.heima.thread;
public class SycronizedMethodDemo {
public static void main(String[] args) {
ThreadDemo demo = new ThreadDemo();
Thread employee1 = new Thread(demo, "窗口1");
Thread employee2 = new Thread(demo, "窗口2");
Thread employee3 = new Thread(demo, "窗口3");
employee1.start();
employee2.start();
employee3.start();
}
}
class ThreadDemo implements Runnable {
static int tickets = 100;
int x = 1;
public ThreadDemo() {
}
/*public synchronized void saltTicket() {
if(tickets>0)
System.out.println(Thread.currentThread().getName() + "卖了第" + tickets + "张票");
tickets--;
try {
Thread.sleep(20);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}*/
public static synchronized void saltTicket() {
if(tickets>0)
System.out.println(Thread.currentThread().getName() + "卖了第" + tickets + "张票");
tickets--;
try {
Thread.sleep(20);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
@Override
public void run() {
while (tickets>0) {
if (x % 2 == 0) {
synchronized (ThreadDemo.class) {
if (tickets > 0) {
System.out.println(Thread.currentThread().getName() + "卖了第" + tickets + "张票");
tickets--;
try {
Thread.sleep(20);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
} else {
saltTicket();//非静态同步函数和静态同步函数测试
}
x++;
}
// super.run();
}
}
结合同步代码块与同步函数一起,发现将同步代码块的锁对象设置为this时,可以锁住非静态同步函数。锁对象设置为class时,可以锁住静态同步函数。
3、Lock
在学习Lock锁之前,先学习多线程的几个方法:
notify()、wait()、notifyAll();
这三个方法都是依赖锁对象的监听器作为标志创建的线程池存在的。
代码演示:
package it.heima.thread;
/*
* 为了让生产者和消费者操作同一个对象,故而使他们操作同一个对象。就在他们内部维护一个produce.
* */
public class NotifyDemo {
public static void main(String[] args) {
Produce p=new Produce();
Customer c=new Customer(p);
Producer pp=new Producer(p);
c.start();
pp.start();
}
}
class Produce {
int price;
String name;
boolean flag;
}
class Customer extends Thread {
private Produce p;
public Customer(Produce p) {
// TODO Auto-generated constructor stub
this.p = p;
}
@Override
public void run() {
buy();
}
public void buy() {
while (true) {
synchronized ("线程池") {
if (p.flag == true) {
System.out.println("顾客花了" + p.price + "买了" + p.name);
p.flag = false;
"线程池".notify();
}else{
try {
"线程池".wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
}
class Producer extends Thread {
private Produce p;
private int x = 1;
public Producer(Produce p) {
this.p = p;
}
@Override
public void run() {
creat();
}
public void creat() {
while (true) {
synchronized ("线程池") {
if (p.flag == false) {
if (x % 2 == 0) {
p.name = "自行车";
p.price = 300;
System.out.println("生产者生产了:" + p.name + " 价格:" + p.price);
"线程池".notify();
p.flag = true;
} else {
p.name = "BMW";
p.price = 10000000;
System.out.println("生产者生产了:" + p.name + " 价格:" + p.price);
"线程池".notify();
p.flag = true;
}
x++;
} else {
try {
"线程池".wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
}
出现异常:当调用notify()方法的对象不是锁对象时,会出现异常:
java.lang.IllegalMonitorStateException
违法的监控状态异常。当某个线程试图等待一个自己并不拥有的对象(O)的监控器或者通知其他线程等待该对象(O)的监控器时,抛出该异常。
违法的监控状态异常。当某个线程试图等待一个自己并不拥有的对象(O)的监控器或者通知其他线程等待该对象(O)的监控器时,抛出该异常。
Lock是一个接口,实现了更为灵活的同步功能。我们用他的子实现类完成同步需求。
Sychronized和Lock的区别
1、Sychroniezed在获取锁与释放锁的过程是隐式的,Lock是显式的。
2、Sychroniezed的监听器是隐式的,Lock是显式的,可以一个lock由多个监听器
Lock的方法:
lock()
unlock()
newCondition()
Condition()的方法:
signal();
await();
signalAll()
这些方法与Object的方法对应
sycronized()------------>lock()和unlock()
wait()------------->await()
notify()------------->signal();
notifyAll()------------->signalAll()
代码实现:
package it.heima.thread;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/*
* 为了让生产者和消费者操作同一个对象,故而使他们操作同一个对象。就在他们内部维护一个produce.
* */
public class NotifyDemo {
public static void main(String[] args) {
Produce p=new Produce();
ReentrantLock r=new ReentrantLock();
Condition cCondition=r.newCondition();
Condition pCondition=r.newCondition();
Customer c=new Customer(p,r,cCondition,pCondition);
Producer pp=new Producer(p,r,cCondition,pCondition);
c.start();
pp.start();
}
}
class Produce {
int price;
String name;
boolean flag;
}
class Customer extends Thread {
private Produce p;
ReentrantLock r;
Condition cCondition;
Condition pCondition;
/*public Customer(Produce p) {
// TODO Auto-generated constructor stub
this.p = p;
}*/
public Customer(Produce p,ReentrantLock r,Condition cCondition,Condition pCondition) {
// TODO Auto-generated constructor stub
this.p = p;
this.r=r;
this.cCondition=cCondition;
this.pCondition=pCondition;
}
@Override
public void run() {
buy();
}
public void buy() {
while (true) {
// synchronized ("线程池") {
r.lock();
if (p.flag == true) {
System.out.println("顾客花了" + p.price + "买了" + p.name);
p.flag = false;
//"线程池".notify();
pCondition.signal();
}else{
try {
//"线程池".wait();
cCondition.await();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
r.unlock();
// }
}
}
}
class Producer extends Thread {
private Produce p;
private int x = 1;
ReentrantLock r;
Condition cCondition;
Condition pCondition;
/*public Producer(Produce p) {
this.p = p;
}*/
public Producer(Produce p,ReentrantLock r,Condition cCondition,Condition pCondition) {
// TODO Auto-generated constructor stub
this.p = p;
this.r=r;
this.cCondition=cCondition;
this.pCondition=pCondition;
}
@Override
public void run() {
creat();
}
public void creat() {
while (true) {
//synchronized ("线程池") {
r.lock();
if (p.flag == false) {
if (x % 2 == 0) {
p.name = "自行车";
p.price = 300;
System.out.println("生产者生产了:" + p.name + " 价格:" + p.price);
// "线程池".notify();
p.flag = true;
cCondition.signal();
} else {
p.name = "BMW";
p.price = 10000000;
System.out.println("生产者生产了:" + p.name + " 价格:" + p.price);
// "线程池".notify();
p.flag = true;
cCondition.signal();
}
x++;
} else {
try {
// "线程池".wait();
pCondition.await();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
r.unlock();
// }
}
}
}