1.线程的同步(并发):
多个线程访问一个资源,那么我们就要是资源安全,方法是使线程同步;
我们使用这个关键字;
线程安全的每次只能进去一个对象,就是给他加了一个锁,这个锁只有一把钥匙,所以只能一个完成后一个在进去;
同步的时候可以选择同步块或者同步方法;(同步又叫做锁定)
package Synchronize;
/**
*
* 线程的同步问题(线程安全不安全)
*
* @author Wang
*
*/
public class Syn {
public static void main(String[] args) {
Web web = new Web();// 创建实体对象
Thread thr1 = new Thread(web, "路人甲");// 创建四个代理 他们来实现多线程的抢票
Thread thr2 = new Thread(web, "黄牛");
Thread thr3 = new Thread(web, "程序员");
Thread thr4 = new Thread(web, "白领");
thr1.start();
thr2.start();
thr3.start();
thr4.start();
}
}
class Web implements Runnable {// 线程不安全的
private int ticketNum = 10;
private boolean flag = true;
@Override
public void run() {
while (flag) {
test6();
//test5();
}
}
public void test1() { // 线程不安全的
if (ticketNum <= 0) {
flag = false;
return;
}
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "抢到了" + ticketNum--);
}
public synchronized void test2() { // 线程安全的 这里加了一个锁
if (ticketNum <= 0) {
flag = false;
return;
}
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "抢到了" + ticketNum--);
}
//线程安全 锁定正确
public void test3(){
//a b c
synchronized(this){ //锁定块 线程安全的
if(ticketNum<=0){
flag=false; //跳出循环
return ;
}
try {
Thread.sleep(500); //模拟 延时
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"抢到了"+ticketNum--);
}
}
//锁定范围不正确 线程不安全
public void test4(){
// c 1
synchronized(this){
//b
if(ticketNum<=0){
flag=false; //跳出循环
return ;
}
}
// b
try {
Thread.sleep(500); //模拟 延时
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"抢到了"+ticketNum--);
}//a -->1
//线程不安全 锁定资源不正确
public void test5(){
//a b c
synchronized((Integer)ticketNum){
if(ticketNum<=0){
flag=false; //跳出循环
return ;
}
try {
Thread.sleep(500); //模拟 延时
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"抢到了"+ticketNum--);
}
}
//锁定的范围有误
public void test6(){
if(ticketNum<=0){
flag=false; //跳出循环
return ;
}
//a b c
synchronized(this){
try {
Thread.sleep(500); //模拟 延时
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"抢到了"+ticketNum--);
}
}
}
2.锁定静态的属性,我们在这里也介绍一下单例设计模式(我们在多线程的创建的时候用到了静态代理设计模式)
/**
* 单例设计模式
* 确保一个类只有一个对象
* 懒汉式 是指在声明静态属性的时候不创建对象 double checking(双重检查提高现成的效率)
* 1、构造器私有化,避免外部直接创建对象
* 2、声明一个私有的静态变量
* 3、创建一个对外的公共的静态方法 访问该变量,如果变量没有对象,创建该对象
*/
synchronized(Jvm.class){//锁住他的字节吗 让他无法创建对象 或者说锁住他的模板 但是再次可以提高效率(double checking )
package Synchronize;
/**
*
* 单例设计模式确保一个类只有一个对象
*
* @author Wang
*
*/
/**
* 单例设计模式:确保一个类只有一个对象
* @author Administrator
*
*/
public class SynchroizeDemo02 {
/**
* @param args
*/
public static void main(String[] args) {
JvmThread thread1 = new JvmThread(100);
JvmThread thread2 = new JvmThread(500);
thread1.start();
thread2.start();
}
}
class JvmThread extends Thread{
private long time;
public JvmThread() {
}
public JvmThread(long time) {
this.time =time;
}
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"-->创建:"+Jvm.getInstance1(time));
}
}
/**
* 单例设计模式
* 确保一个类只有一个对象
* 懒汉式 声明静态变量的时候没有创建对象 double checking 双重检查提高效率
* 1、构造器私有化,避免外部直接创建对象
* 2、声明一个私有的静态变量
* 3、创建一个对外的公共的静态方法 访问该变量,如果变量没有对象,创建该对象
*/
class Jvm {
//声明一个私有的静态变量
private static Jvm instance =null;
//构造器私有化,避免外部直接创建对象
private Jvm(){
}
//创建一个对外的公共的静态方法 访问该变量,如果变量没有对象,创建该对象
public static Jvm getInstance(long time){ //线程不安全的创建对像的地址都不一样
if(instance == null){
try {
Thread.sleep(time); //延时 ,放大错误
} catch (InterruptedException e) {
e.printStackTrace();
}
instance =new Jvm();
}
return instance;
}
//创建一个对外的公共的静态方法 访问该变量,如果变量没有对象,创建该对象
public static Jvm getInstance1(long time){
synchronized(Jvm.class){//锁住他的字节吗 让他无法创建对象 或者说锁住他的模板 但是再次可以提高效率
if(instance == null){//存在对象也需要等待
try {
Thread.sleep(time); //延时 ,放大错误
} catch (InterruptedException e) {
e.printStackTrace();
}
instance =new Jvm();
}
}
return instance;
}
//创建一个对外的公共的静态方法 访问该变量,如果变量没有对象,创建该对象
public static Jvm getInstance2(long time){
// c d e -->效率 提供 已经存在对象的访问效率
if(null==instance){ //这里我们用double-checking 的方法来提高现成的效率
// a b
synchronized(Jvm.class){
if(null==instance ){
try {
Thread.sleep(time); //延时 ,放大错误
} catch (InterruptedException e) {
e.printStackTrace();
}
instance =new Jvm();
}
}
}//a
return instance;
}
}
单例设计方法的懒汉与饿汉式
package Synchronize;
/**
* 单例创建的方式
* 1、懒汉式
* 1)、构造器私有化
* 2)、声明私有的静态属性
* 3)、对外提供访问属性的静态方法,确保该对象存在
*
* @author Administrator
*
*/
public class Demo03 {
private static Demo03 instance;
private Demo03(){
}
public static Demo03 getInstance (){
if(instance == null){ //提供效率
synchronized(Demo03.class){
if(null==instance){ //安全
instance =new Demo03();
}
}
}
return instance;
}
}
/**
* 饿汉式
1)、构造器私有化
* 2)、声明私有的静态属性,同时创建该对象
* 3)、对外提供访问属性的静态方法
* @author Administrator
*
*/
class MyJvm2 {
private static MyJvm2 instance =new MyJvm2();
private MyJvm2(){
}
public static MyJvm2 getInstance (){//饿汉式是不需要同步的也不需要判断对象是否存在因为 类会在时候的加载他的属性 那么就会在加载第一句的时候创建对象
return instance;
}
}
/**
* 类在使用的时候加载 ,延缓加载时间
*/
class MyJvm3 {
private static class JVMholder{//内部类 这里就会提高效率 只有getInstance ()被调用的时候他才会被加载 跟MyJvm03加载就没什么关系了
private static MyJvm3 instance =new MyJvm3();
}
private MyJvm3(){
}
public static MyJvm3 getInstance (){
return JVMholder.instance;
}
}
注意:懒汉式与饿汉式都有提高效率的方法
3.过多的同步方法可能会造成死锁;
package Synchronize;
/**
* 过多的同步方法可能造成死锁
* @author Wang
*
*/
public class Demo04 {
/**
* @param args
*/
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) {
super();
this.goods = goods;
this.money = money;
}
@Override
public void run() {
while(true){
test();
}
}
public void test(){
synchronized(goods){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized(money){
}
}
System.out.println("一手给钱");
}
}
class Test2 implements Runnable{
Object goods ;
Object money ;
public Test2(Object goods, Object money) {
super();
this.goods = goods;
this.money = money;
}
@Override
public void run() {
while(true){
test();
}
}
public void test(){
synchronized(money){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized(goods){
}
}
System.out.println("一手给货");
}
}
4.解决死锁的办法 生产者消费者模式:(注意这个不是设计模式)
设计模式:是将类于类的关系;
package lock;
/**
* 一个场景,共同的资源 生产者消费者模式 信号灯法 wait() :等待,释放锁 sleep 不释放锁 notify()/notifyAll():唤醒 与
* synchronized
*
* @author Administrator
*
*/
public class Moive {
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(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("生产了:" + pic);
// 生产完毕
this.pic = pic;
// 通知消费
this.notify();
// 生产者停下
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("消费了" + pic);
// 消费完毕
// 通知生产
this.notifyAll();
// 消费停止
this.flag = true;
}
}
package lock;
public class Player implements Runnable {
private Moive m;
Player(Moive m) {
this.m = m;
}
@Override
public void run() {
for (int i = 0; i < 20; i++) {
if (i % 2 == 0) {
m.play("缝纫机乐队");
} else {
m.play("最好的我们");
}
}
}
}
package lock;
public class Watcher implements Runnable {
private Moive m;
Watcher(Moive m) {
this.m = m;
}
@Override
public void run() {
for (int i = 0; i < 20; i++) {
m.watch();
}
}
}
package lock;
public class Apply {
public static void main(String[] args) {
Moive m = new Moive();
Player p = new Player(m);
Watcher w = new Watcher(m);
new Thread(p).start();
new Thread(w).start();
}
}
5.任务的调度
package task;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;
/**
*
* Timer()
* schedule(TimerTask task, Date time)
* schedule(TimerTask task, Date firstTime, long period)
* 可以自学一下 quartz(框架) 关于任务调度的
*
* @author Wang
*
*/
public class Time {
public static void main(String[] args) {
Timer timer =new Timer();
timer.schedule(new TimerTask(){ //使用匿名内部类 创建一个对象 因为继承了Runnable所以还要重写run() 方法
@Override
public void run() {
System.out.println("so easy....");
}}, new Date(System.currentTimeMillis()+1000), 2000);//1s之后开始执行 每间隔两秒执行一次
}
}
注意:
wait() :等待,释放锁; sleep 不释放锁; notify()/notifyAll(): 唤醒 他们都必须要与 synchronized连用才有效果;
线程安全的效率就会低;