JAVA自学教程之线程的同步。
继续以卖票为例
一、线程安全问题的解决
同步的第一种表现形式:同步代码块
思路:
将多条操作共享数据的线程代码封装起来,当有线程在执行这些代码的时候,其他线程是不允许参与运算的,必须要当期线程把代码执行完毕后,其他线程才可以参与运算
在java中用同步代码块解决这个问题
同步代码块格式:
synchronized(对象)
{
需要被同步的代码部分
}
- class Ticket implements Runnable
- {
- private int num = 100;
- Object god = new Object();//也可以自定义,建议使用已有的
- public void run()
- {
- while(true)
- {
- synchronized(god) //同步
- {
- if(num>0)
- {
- try
- {
- Thread.sleep(10);
- }
- catch (InterruptedException e)
- {
- // TODO: handle exception
- }
- System.out.println(Thread.currentThread().getName()+”..sale..”+num–);
- }
- }
- }
- }
- }
- public class Main
- {
- public static void main(String[] args)
- {
- Ticket t = new Ticket();
- Thread j1 = new Thread(t);
- Thread j2 = new Thread(t);
- Thread j3 = new Thread(t);
- Thread j4 = new Thread(t);
- j1.start(); j2.start();
- j3.start(); j4.start();
- }
- }
class Ticket implements Runnable
{
private int num = 100;
Object god = new Object();//也可以自定义,建议使用已有的
public void run()
{
while(true)
{
synchronized(god) //同步
{
if(num>0)
{
try
{
Thread.sleep(10);
}
catch (InterruptedException e)
{
// TODO: handle exception
}
System.out.println(Thread.currentThread().getName()+"..sale.."+num--);
}
}
}
}
}
public class Main
{
public static void main(String[] args)
{
Ticket t = new Ticket();
Thread j1 = new Thread(t);
Thread j2 = new Thread(t);
Thread j3 = new Thread(t);
Thread j4 = new Thread(t);
j1.start(); j2.start();
j3.start(); j4.start();
}
}
Object的对象就好比一把锁,对同步进行监视操作,当有线程在执行,其他线程不能执行
同步的好处:解决了线程的安全问题
同步的弊端:当一个线程sleep时,释放执行权,执行权会给其他线程,然后进行判断同步锁,判断完又进不去,所以相对以前会降低效率,是在可承受的范围内
二、同步的前提
如果出现,同步后安全问题还存在,就必须了解同步的前提
前提:同步中必须有多个线程并使用同一个锁(一个线程就没必要同步,多个锁就失去同步的价值)
三、同步的第二种表现形式:同步函数
- /*
- * 需求:
- * 两个人到银行存钱,每次存10,每个人都是三次
- *
- * */
- class Bank
- {
- private int sum;
- private Object obj = new Object();
- //同步代码代码块表现形式
- /*public void add(int num)
- {
- synchronized(obj)
- {
- sum += num;
- try {
- Thread.sleep(10);
- } catch (InterruptedException e) {
- // TODO: handle exception
- }
- System.out.println(“sum = “+sum);
- }
- }*/
- //同步函数表现形式
- public synchronized void add(int num)
- {
- sum += num;
- try {
- Thread.sleep(10);
- } catch (InterruptedException e) {
- // TODO: handle exception
- }
- System.out.println(“sum = “+sum);
- }
- }
- class Custom implements Runnable
- {
- private Bank bank = new Bank();
- public void run()
- {
- for(int i = 0;i<3;i++)
- {
- bank.add(10);
- }
- }
- }
- class Main
- {
- public static void main(String[] args)
- {
- Custom tCustom = new Custom();
- Thread j1 = new Thread(tCustom);
- Thread j2 = new Thread(tCustom);
- j1.start();
- j2.start();
- }
- }
/*
* 需求:
* 两个人到银行存钱,每次存10,每个人都是三次
*
* */
class Bank
{
private int sum;
private Object obj = new Object();
//同步代码代码块表现形式
/*public void add(int num)
{
synchronized(obj)
{
sum += num;
try {
Thread.sleep(10);
} catch (InterruptedException e) {
// TODO: handle exception
}
System.out.println("sum = "+sum);
}
}*/
//同步函数表现形式
public synchronized void add(int num)
{
sum += num;
try {
Thread.sleep(10);
} catch (InterruptedException e) {
// TODO: handle exception
}
System.out.println("sum = "+sum);
}
}
class Custom implements Runnable
{
private Bank bank = new Bank();
public void run()
{
for(int i = 0;i<3;i++)
{
bank.add(10);
}
}
}
class Main
{
public static void main(String[] args)
{
Custom tCustom = new Custom();
Thread j1 = new Thread(tCustom);
Thread j2 = new Thread(tCustom);
j1.start();
j2.start();
}
}
验证同步函数的锁是什么?(了解)
- class Ticket implements Runnable
- {
- private int num = 100;
- Object god = new Object();//也可以自定义,建议使用已有的
- boolean flag = true;
- public void run()
- {
- if(flag==true)
- {
- while(true)
- {
- synchronized(this) //同步
- {
- if(num>0)
- {
- try
- {
- Thread.sleep(10);
- }
- catch (InterruptedException e)
- {
- // TODO: handle exception
- }
- System.out.println(Thread.currentThread().getName()+”..obj..”+num–);
- }
- }
- }
- }
- else {
- while(true)
- this.show();
- }
- }
- public synchronized void show()
- {
- if(num>0)
- {
- try
- {
- Thread.sleep(10);
- }
- catch (InterruptedException e)
- {
- // TODO: handle exception
- }
- System.out.println(Thread.currentThread().getName()+”..fu..”+num–);
- }
- }
- }
- class Main
- {
- public static void main(String[] args)
- {
- Ticket t = new Ticket();
- Thread j1 = new Thread(t);
- Thread j2 = new Thread(t);
- j1.start();
- try
- {
- Thread.sleep(10);
- } catch (InterruptedException e)
- {
- // TODO: handle exception
- }
- t.flag = false;
- j2.start();
- }
- }
class Ticket implements Runnable
{
private int num = 100;
Object god = new Object();//也可以自定义,建议使用已有的
boolean flag = true;
public void run()
{
if(flag==true)
{
while(true)
{
synchronized(this) //同步
{
if(num>0)
{
try
{
Thread.sleep(10);
}
catch (InterruptedException e)
{
// TODO: handle exception
}
System.out.println(Thread.currentThread().getName()+"..obj.."+num--);
}
}
}
}
else {
while(true)
this.show();
}
}
public synchronized void show()
{
if(num>0)
{
try
{
Thread.sleep(10);
}
catch (InterruptedException e)
{
// TODO: handle exception
}
System.out.println(Thread.currentThread().getName()+"..fu.."+num--);
}
}
}
class Main
{
public static void main(String[] args)
{
Ticket t = new Ticket();
Thread j1 = new Thread(t);
Thread j2 = new Thread(t);
j1.start();
try
{
Thread.sleep(10);
} catch (InterruptedException e)
{
// TODO: handle exception
}
t.flag = false;
j2.start();
}
}
同步函数的使用的锁是this
同步函数和同步代码块的区别:
同步函数的锁是固定的this,同步代码块的锁是任意的
所以同步时,建议使用同步代码块
验证静态同步函数的锁是什么?(了解)
静态同步函数的锁不是this,因为根本没有this
- class Ticket implements Runnable
- {
- private static int num = 100;
- Object god = new Object();//也可以自定义,建议使用已有的
- boolean flag = true;
- public void run()
- {
- if(flag==true)
- {
- while(true)
- {
- synchronized(this.getClass())
- //synchronized(Ticket.class)
- {
- if(num>0)
- {
- try
- {
- Thread.sleep(10);
- }
- catch (InterruptedException e)
- {
- // TODO: handle exception
- }
- System.out.println(Thread.currentThread().getName()+”..obj..”+num–);
- }
- }
- }
- }
- else {
- while(true)
- this.show();
- }
- }
- public static synchronized void show()
- {
- if(num>0)
- {
- try
- {
- Thread.sleep(10);
- }
- catch (InterruptedException e)
- {
- // TODO: handle exception
- }
- System.out.println(Thread.currentThread().getName()+”..fu..”+num–);
- }
- }
- }
- class Main
- {
- public static void main(String[] args)
- {
- Ticket t = new Ticket();
- Thread j1 = new Thread(t);
- Thread j2 = new Thread(t);
- j1.start();
- try
- {
- Thread.sleep(10);
- } catch (InterruptedException e)
- {
- // TODO: handle exception
- }
- t.flag = false;
- j2.start();
- }
- }
class Ticket implements Runnable
{
private static int num = 100;
Object god = new Object();//也可以自定义,建议使用已有的
boolean flag = true;
public void run()
{
if(flag==true)
{
while(true)
{
synchronized(this.getClass())
//synchronized(Ticket.class)
{
if(num>0)
{
try
{
Thread.sleep(10);
}
catch (InterruptedException e)
{
// TODO: handle exception
}
System.out.println(Thread.currentThread().getName()+"..obj.."+num--);
}
}
}
}
else {
while(true)
this.show();
}
}
public static synchronized void show()
{
if(num>0)
{
try
{
Thread.sleep(10);
}
catch (InterruptedException e)
{
// TODO: handle exception
}
System.out.println(Thread.currentThread().getName()+"..fu.."+num--);
}
}
}
class Main
{
public static void main(String[] args)
{
Ticket t = new Ticket();
Thread j1 = new Thread(t);
Thread j2 = new Thread(t);
j1.start();
try
{
Thread.sleep(10);
} catch (InterruptedException e)
{
// TODO: handle exception
}
t.flag = false;
j2.start();
}
}
静态同步函数的锁 该函数所属字节码文件对象
可以使用getClass方法获取,也可以使用 当前 类名.class获取