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获取