线程安全之同步方法
当线程共享一个资源时会由于互抢cup而造成对资源的操作不安全问题,所以要用同步方法或同步代码块进行代码同步处理操作,保证线程安全
同步代码块
synchronized(Object o){
}
将要进行的代码放入大括号内,小括号内放资源类对象,也被称为:锁,
一旦有线程进入了大括号在执行完最后一行代码之前,其他线程是进不来的
所以保证了在一个线程对一个资源进行操作完成之前不会有别的线进来抢,从而保证了线程的安全.
package com.qf.demo;
public class Test {
public static void main(String[] args) {
Window window = new Window();
Thread thread = new Thread(window,"二狗");
Thread thread2 = new Thread(window,"三狗");
Thread thread3 = new Thread(window,"四狗");
Thread thread4 = new Thread(window,"五狗");
thread.start();
thread2.start();
thread3.start();
thread4.start();
}
}
/**
* 使用同步代码块
* 1 确定要被同步的代码
* 2 用同步代码块 将要被同步的代码进行同步
* synchronized(object){
* 被同步的代码
* }
* @author Administrator
*
*/
class Window implements Runnable{
int ticket= 100;
//Window object = new Window();// 锁的对象必须是唯一的 多个线程 公用一把锁
// 如果是多把锁, 就相当于没加锁
// 资源类 只能创建一个对象, 可以利用资源类对象 this
@Override
public void run() {
while(true){
synchronized (this) {// 锁是object 任意类型的 任意锁, 互斥锁
if(ticket>0){
ticket--;
try {
Thread.sleep(1000);// 会释放cpu , 但是没有释放锁资源
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"卖了1张票,还剩"+ticket);
}else{
break;
}
}
}
}
}
同步方法
public synchronized void printNumber(int num){
}
同步方法要写在资源类内部,而且要求锁是唯一的,所以锁用this来调用
package com.qf.demo;
public class Test3 {
public static void main(String[] args) {
Window2 window2 = new Window2();
Thread thread = new Thread(window2,"马什么梅");
Thread thread2 = new Thread(window2,"什么冬梅");
Thread thread3= new Thread(window2,"马东什么");
Thread thread4 = new Thread(window2,"马冬梅啊");
thread.start();
thread2.start();
thread3.start();
thread4.start();
}
}
/**
* 同步方法
*
* @author Administrator
*
*/
class Window2 implements Runnable {
int ticket = 100;
@Override
public void run() {// 不要在run 方法上面添加synchronized
while (true) {
if(!saleTicket()){
break;
}
}
}
// 同步方法 锁是 this 还要要求 锁是 唯一的 , 同步方法要写在资源类里面
public synchronized boolean saleTicket(){
if (ticket > 0) {
ticket--;
try {
Thread.sleep(1000);// 会释放cpu , 但是没有释放锁资源
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "卖了1张票,还剩" + ticket);
return true;
} else{
return false;
}
}
}
懒汉模式
之前说过懒汉模式是线程不安全的,现在我们对他进行改造一下就可以变成线程安全的
package com.qf.demo2;
public class LazyInstance {
private LazyInstance(){
}
private static LazyInstance instance;
// 加上一个同步代码块或者是同步方法 就是能实现 线程安全的单例
public static LazyInstance getInstance(){
// 双重检查, 双重锁
if(instance == null){// 为了 防止所有的线程都要去判断锁,
//尽可能少的让线程判断锁, 就可以调高效率
synchronized (LazyInstance.class) {
if(instance==null){
//线程一 null 并且没有创建对象
// 线程二 null 创建对象了
instance = new LazyInstance();
}
}
}
return instance;
}
public static synchronized void a(){
if(instance==null){
//线程一 null 并且没有创建对象
// 线程二 null 创建对象了
instance = new LazyInstance();
}
}
}