1.同步代码块
synchronized(Object o){
//同步代码
}
public class WindowTest2 {
public static void main(String[] args) {
new Window2("窗口1").start();
new Window2("窗口2").start();
new Window2("窗口3").start();
}
}
class Window2 extends Thread{
private static int ticket=100;
private static Object obj = new Object(); //同步锁对象,注意这里必须让同步锁对象唯一,使用static修饰
public Window2(String str){
super(str);
}
@Override
public void run() {
while (true){
synchronized(obj){ //也可以使用Window2.class,反射机制
if (ticket>0){
System.out.println(Thread.currentThread().getName()+"售出:"+ticket);
ticket--;
}else {
break;
}
}
}
}
}
当使用实现Runnable接口的时候也可以用this来充当同步锁对象
2.同步方法
实现Runnable接口的方式中,同步方法的同步锁对象为this
public static synchronized void(){}
public class WindowTest3 {
public static void main(String[] args) {
Window3 Window3 = new Window3();
Thread t1 = new Thread(Window3, "窗口1");
Thread t2 = new Thread(Window3, "窗口2");
Thread t3 = new Thread(Window3, "窗口3");
t1.start();
t2.start();
t3.start();
}
}
class Window3 implements Runnable {
private int ticket = 100;
@Override
public void run() {
while (true){
show();
}
}
private synchronized void show(){
if(ticket>0){
System.out.println(Thread.currentThread().getName()+"售"+ticket--);
}
}
}
使用继承Thread类时:
如果同步方法不定义成静态的同步方法时,默认同步锁对象为this,这样的话达不到同步的作用,因为同步锁对象不唯一
应该将同步方法定义成静态的同步方法,此时的同步锁对象则为 当前类名.class 这样才能达到同步的效果
public class WindowTest4 {
public static void main(String[] args) {
new Window4("窗口1").start();
new Window4("窗口2").start();
new Window4("窗口3").start();
}
}
class Window4 extends Thread{
private static int ticket=100;
public Window4(String str){
super(str);
}
@Override
public void run() {
while (true){
show();
}
}
private static synchronized void show(){ //静态同步方法的同步锁对象为当前类,即.class,非静态方法的同步锁对象则为this
if(ticket>0){
System.out.println(Thread.currentThread().getName()+"售"+ticket--);
}
}
}
3.Lock锁
public class LockTest {
public static void main(String[] args) {
Test test = new Test();
new Thread(test).start();
new Thread(test).start();
new Thread(test).start();
}
}
class Test implements Runnable{
private int ticket = 100;
private Lock lock = new ReentrantLock();
@Override
public void run() {
while (true){
lock.lock(); //加锁
if (ticket>0){
System.out.println(Thread.currentThread().getName()+"售:"+ticket+" 张票");
ticket--;
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}else {
break;
}
lock.unlock(); //一般放在finally中,释放锁
}
}
}
4.线程通信
主要方法wait(),notify(),notifyAll()这几个方法必须在同步代码块或同步方法中使用
生产者消费者问题:
//生产者
public class Productor extends Thread {
private Count count;
public Productor(Count count, String name) {
super(name);
this.count = count;
}
@Override
public void run() {
while (true) {
count.ProductProduction();
}
}
}
//消费者
public class Consumer extends Thread {
private Count count;
public Consumer(Count count, String name) {
super(name);
this.count = count;
}
@Override
public void run() {
while (true) {
count.ConsumeProduction();
}
}
}
//共享资源
public class Count {
private int count=0;
//同步方法
public synchronized void ProductProduction(){
if (count<20){
count++;
System.out.println(Thread.currentThread().getName()+"生产第"+ count + "件产品");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
notify(); //当有产品时,告知消费者可以进行消费,唤醒消费者线程
}else {
try {
wait(); //当产品数为20,已满的时候则不能在进行生产,进入阻塞状态
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public synchronized void ConsumeProduction(){
if(count<=0){
try {
wait(); //产品数为0时,消费进程进入阻塞状态
} catch (InterruptedException e) {
e.printStackTrace();
}
}else{
System.out.println(Thread.currentThread().getName()+"消费第"+ count + "件产品");
count--;
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
notify(); //唤醒已阻塞的线程
}
}
}
public class Demo {
public static void main(String[] args) {
Count count = new Count();
Productor productor = new Productor(count, "甲");
Consumer consumer = new Consumer(count, "乙");
productor.start();
consumer.start();
}
}