一、同步:synchronized
同步 并发 多个线程访问同一资源,确保资源安全---->线程安全
- 同步块:
Synchronized(引用类型 | this | 类.class){
}
- 同步方法: public static synchronized void.... ---->Web12306
web12306代码实现:
package com.cust.syn;
/**
*
* 描述:同步 并发 多个线程访问同一资源
* synchronized 线程安全
* @author cookie
*/
public class SynDemo01 {
public static void main(String[] args) {
//真实角色
Web12306 w = new Web12306();
//三个代理角色
Thread t1 = new Thread(w,"路人甲");
Thread t2 = new Thread(w,"黄牛乙");
Thread t3 = new Thread(w,"攻城狮");
t1.start();
t2.start();
t3.start();
}
}
class Web12306 implements Runnable {
private boolean flag = true;
int num = 10;
@Override
public void run() {
while(flag){
test5();
}
}
//锁定资源不正确 --->线程不安全 速率比较高
public void test5() {
// a b c
synchronized ((Integer) num) { // 锁定
if (num <= 0) {
flag = false;// 线程结束
return;
}
// a b c
try {
Thread.sleep(500);// Runnable无法往外抛出异常
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "抢到了第张"+ num-- + "票");
}
}// a b = 0 c = -1
//锁定范围不正确 --->线程不安全 速率比较高
public void test4(){
// a b c
synchronized(this){ // 锁定 调用此方法的对象 即 Web12306
if(num <=0){
flag = false;//线程结束
return;
}
}
// a b c
try {
Thread.sleep(500);//Runnable无法往外抛出异常
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"抢到了第张"+ num-- +"票");
}//a b = 0 c = -1
//锁定同步块 --->线程安全 速率较低
public void test3(){
synchronized(this){ // 锁定 调用此方法的对象 即 Web12306
if(num <=0){
flag = false;//线程结束
return;
}
try {
Thread.sleep(500);//Runnable无法往外抛出异常
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"抢到了第张"+ num-- +"票");
}
}
//锁定方法 --->线程安全 速率较低
public synchronized void test2(){
if(num <=0){
flag = false;//线程结束
return;
}
try {
Thread.sleep(500);//Runnable无法往外抛出异常
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"抢到了第张"+ num-- +"票");
}
//并发 不处理 ---->线程不安全 速率较低
public void test1(){
if(num <=0){
flag = false;//线程结束
return;
}
try {
Thread.sleep(500);//Runnable无法往外抛出异常
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"抢到了第张"+ num-- +"票");
}
}
二、单例模式
懒汉式 和 饿汉式
package com.cust.syn;
/**
* 单例模式
* gc JVM 垃圾桶 Runtime
* 懒汉式: double checking 双重检查
* 1.构造器私有化
* 2.声明一个私有的静态变量
* 3.创建一个共有的静态方法,访问变量,并确保有变量
* 饿汉式:
*
* @author cookie
*/
public class SingletonDemo {
}
/**
* 懒汉式: double checking 双重检查
* 1.构造器私有化
* 2.声明一个私有的静态变量
* 3.创建一个共有的静态方法,访问变量,并确保有变量
* @author cookie
*/
class JVM{
private static JVM jvm;
private JVM(){
}
public static JVM getInstance(){
if(null == jvm){ //提高效率,在对象已经存在的情况下不进入该方法
synchronized(JVM.class){ //静态方法中不能调用this
if(null==jvm){ //如果不存在,则创建对象 安全
jvm = new JVM();
}
}
}
return jvm;
}
}
/**
* 饿汉式:
* 1.构造器私有化
* 2.声明一个私有的静态变量,并同时实例化该变量
* 3.创建一个共有的静态方法,访问变量
* @author cookie
*/
class JVM2{
private static JVM2 jvm = new JVM2();
private JVM2(){
}
public static JVM2 getInstance(){ //不使用这个方法,变量可能被初始化
return jvm;
}
}
/**
* 类在使用时加载,延缓加载时间(MyJvm) 饿汉式推荐
* @author cookie
*/
class JVM3{
private static class MyJvm{
private static JVM3 jvm = new JVM3();
}
private JVM3(){
}
public static JVM3 getInstance(){//不使用这个方法,不会加载MyJvm
return MyJvm.jvm;
}
}
三、死锁:过多的同步容易造成死锁
/**
*
* 描述:死锁:过多的同步容易造成死锁
* @author cookie
*/
public class SynDemo03 {
public static void main(String[] args) {
Object g = new Object();
Object m = new Object();
Test t1 = new Test(g,m);
Test2 t2 = new Test2(g,m);
Thread proxy = new Thread(t1);
Thread proxy2 = new Thread(t2);
proxy.start();
proxy2.start();
}
}
class Test implements Runnable{
Object goods;
Object money;
public Test(Object goods, Object money) {
this.goods = goods;
this.money = money;
}
@Override
public void run() {
test();
}
public void test(){
synchronized(goods){
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized(money){
}
}
System.out.println("一手给钱");
}
}
class Test2 implements Runnable{
Object goods;
Object money;
public Test2(Object goods, Object money) {
this.goods = goods;
this.money = money;
}
@Override
public void run() {
test();
}
public void test(){
synchronized(money){
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized(goods){
}
}
System.out.println("一手给货");
}
}
四、解决死锁:生产者消费者 信号量法
package com.cust.pro;
/**
* 一个场景 共同的资源 生产者消费者模式 信号灯法 Object: wait() 释放锁 等待 sleep()不释放锁
* notify()/notifyAll() 唤醒等待
*
* @author cookie
*/
class Movie {
private String pic;
// 信号灯
// 信号灯法
// flag---->T 生产者生产,消费者等待,生产完生产毕后,唤醒消费者
// flag---->F 消费者消费,生产者等待,消费者消费完毕后,唤醒生产者
private boolean flag = true;
public synchronized void play(String pic) {
if (!flag) {// 消费者消费 生产者等待
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
try {
Thread.sleep(100);
} catch (InterruptedException e1) {
e1.printStackTrace();
}
// 生产结束
this.pic = pic;
System.out.println("生产了:" + pic);
// 唤醒消费者,
this.notifyAll();
// 生产者结束
this.flag = false;
}
public synchronized void watch() {
if (flag) {// 生产者生产,消费者等待
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 消费者消费
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 消费完毕
System.out.println("消费了:" + this.pic);
// 唤醒生产者
this.notify();
// 消费者等待
this.flag = true;
}
}
class Player implements Runnable{
private Movie m;
public Player(Movie m) {
this.m = m;
}
@Override
public void run() {
for (int i = 0; i < 20; i++) {
if(0==i%2){
m.play("左青龙");
}else{
m.play("右白虎");
}
}
}
}
class Watcher implements Runnable{
private Movie m;
public Watcher(Movie m) {
this.m = m;
}
@Override
public void run() {
for (int i = 0; i < 20; i++) {
m.watch();
}
}
}
public class App {
public static void main(String[] args) {
//共同的资源
Movie m = new Movie();
//多线程
Player p = new Player(m);
Watcher w = new Watcher(m);
new Thread(p).start();
new Thread(w).start();
}
}