在java中由于同一进程的多个线程共享同一片存储空间,在带来方便的同时,也带来了访问冲突这个严重的问题。Java语言提供了专门机制以解决这种冲突,有效避免了同一个数据对象被多个线程同时访问。 多个线程访问同一份资源,总是会出现问题。所以我们只需针对方法提出一套机制,这套机制就是synchronized关键字,它包括两种用法:synchronized方法和synchronized块。
下面就是具体的实例:
public class SynDemo01 {
public static void main(String[] args) {
//真实角色
Web12306 web = new Web12306();
//代理
Thread t1 = new Thread(web, "路人甲");
Thread t2 = new Thread(web, "黄牛乙");
Thread t3 = new Thread(web, "攻城狮");
t1.start();
t2.start();
t3.start();
}
}
class Web12306 implements Runnable {
private int num = 12;//1到50号
private boolean flag=true;
@Override
public void run(){
while(flag) {
// test1();
test5();
}
}
public void test6(){
if(num <= 0){
flag = false;//跳出循环
return ;
}
//a、b、c同步等待,然后一个一个进去
synchronized(this) {
try {
Thread.sleep(500);//t1、t2、t3可能都在等待,num可能相同或为-1
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "抢到了" + num--);
}
}
//锁定资源不正确
public void test5(){
synchronized((Integer)num) { //因为synchronized(this|类.class|引用类型),所以这里num需要强制转型
if(num <= 0){
flag = false;//跳出循环
return ;
}
try {
Thread.sleep(500);//t1、t2、t3可能都在等待,num可能相同或为-1
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "抢到了" + num--);
}
}
//锁定范围不正确
public void test4(){
//在这里a、b、c因此进入
synchronized(this) {
if(num <= 0){
flag = false;//跳出循环
return ;
}
}
//然而下面依然是同步的,所以可能出现a、b、c同时在执行
try {
Thread.sleep(500);//t1、t2、t3可能都在等待,num可能相同或为-1
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "抢到了" + num--);
}
//线程块
public void test3(){
synchronized(this) {
if(num <= 0){
flag = false;//跳出循环
return ;
}
try {
Thread.sleep(500);//t1、t2、t3可能都在等待,num可能相同或为-1
} 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);//t1、t2、t3可能都在等待,num可能相同或为-1
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "抢到了" + num--);
}
//线程不安全
public void test1(){
if(num <= 0){
flag = false;//跳出循环
}
try {
Thread.sleep(500);//t1、t2、t3可能都在等待,num可能相同或为-1
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "抢到了" + num--);
}
}
单例设计模式
public class Demo02 {
public static void main(String[] args) {
Jvm j1 = Jvm.getinstance();
Jvm j2 = Jvm.getinstance();
System.out.println(j1+"------->"+j2);//单线程因为是同一个对象所以地址相等
JvmThread t1 = new JvmThread(100);
JvmThread t2 = new JvmThread(500);
t1.start();
t2.start(); //虽然访问是同一份资源,资源就是静态的Jvm2但是地址并不是一样
}
}
class JvmThread extends Thread{
private long time;
public JvmThread(long time) {
this.time = time;
}
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"--->"+Jvm2.getinstance(time));
}
}
/**
* 单例设计模式--多线程测试
* 懒汉式
* @author Administrator
*
*/
class Jvm2{
private static Jvm2 instance = null;
private Jvm2(){
}
public static Jvm2 getinstance(long time){
if(null==instance){
try {
Thread.sleep(time); //放大发生错误的概率
} catch (InterruptedException e) {
e.printStackTrace();
}
instance = new Jvm2();
}
return instance;
}
}
/**
* 单例设计模式
* 懒汉式
* 确保一个类只有一个对象
* 1、确保构造器私有化,避免外部对象直接创建对象
* 2、申明一个私有的静态变量
* 3、创建一个对外的公共静态方法,访问该变量,如果变量没有对象就创建对象
* @author Administrator
*
*/
class Jvm{
private static Jvm instance = null;
private Jvm(){
}
public static Jvm getinstance(){
if(null==instance){
instance = new Jvm();
}
return instance;
}
}
输出结果:
cn.feng.Testsynchronized.Jvm@4706e02e------->cn.feng.Testsynchronized.Jvm@4706e02e
Thread-0--->cn.feng.Testsynchronized.Jvm2@48ffb301
Thread-1--->cn.feng.Testsynchronized.Jvm2@b412c18
改进后为:
/**
* 单例设计模式--多线程测试,加入锁改进,效率提高
* 懒汉式 DoubleCheaking
* @author Administrator
*
*/
class Jvm5{
private static Jvm5 instance = null;
private Jvm5(){
}
//虽然可以锁定,但是效率不高
public static Jvm5 getinstance(long time){
//如果a、b、c三个对象,a和b先进入,已经创建对象之后,c就没必要继续执行一遍
if(null==instance){
synchronized(Jvm5.class){
if(null==instance){
try {
Thread.sleep(time); //放大发生错误的概率
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
instance = new Jvm5();
}
return instance;
}
}
单例的其他创建方式
/**
* 单例设计模式的集中创建方式
* @author Administrator
*
*/
public class Demo03 {
}
/**
* 单例设计模式
* 恶汉式
* 确保一个类只有一个对象
* 1、确保构造器私有化,避免外部对象直接创建对象
* 2、申明一个私有的静态变量,同时创建对象
* 3、创建一个对外的公共静态方法,访问该变量
* 双重判断
* @author Administrator
*
*/
class Jvm6{
private static Jvm6 instance = new Jvm6();
private Jvm6(){
}
public static Jvm6 getinstance(){
return instance;
}
}
class Jvm7{
//改进恶汉式,延缓了加载时间,在加载Jvm3的时候,不一定会初始化,因为初始化在方法中,
//而上面的类是一定会初始化的。
private static class JvmInitial{
private static Jvm7 instance = new Jvm7();
}
private Jvm7(){
}
public static Jvm7 getinstance(){
return JvmInitial.instance;
}
}
/**
* 单例设计模式
* 懒汉式
* 确保一个类只有一个对象
* 1、确保构造器私有化,避免外部对象直接创建对象
* 2、申明一个私有的静态变量
* 3、创建一个对外的公共静态方法,访问该变量,如果变量没有对象就创建对象
* 双重判断
* @author Administrator
*
*/
class Jvm8{
private static Jvm8 instance = null;
private Jvm8(){
}
public static Jvm8 getinstance(){
if(null==instance){
synchronized(Jvm8.class){
if(null==instance){
instance = new Jvm8();
}
}
}
return instance;
}
}