多线程——同步代码块、同步函数、静态同步函数
------
Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------
线程安全问题解决思路:
就是将多条操作共享数据的线程代码封装起来,当有线程在执行这些代码的时候,
其他线程是不可以参与运算的。
必须要当前线程把这些代码都执行完毕后,其他线程才可以参与运算。
同步代码块
在Java中,用同步代码块就可以解决这个问题。
同步代码块(同步锁)的格式:
synchronized(对象){
需要被同步的代码;
}
锁可以是任意对象。
就是将多条操作共享数据的线程代码封装起来,当有线程在执行这些代码的时候,
其他线程是不可以参与运算的。
必须要当前线程把这些代码都执行完毕后,其他线程才可以参与运算。
同步代码块
在Java中,用同步代码块就可以解决这个问题。
同步代码块(同步锁)的格式:
synchronized(对象){
需要被同步的代码;
}
锁可以是任意对象。
示例:
class Ticket implements Runnable{
private int num=100;
Object obj=new Object();
public void run(){
while(true){
<span style="color:#ff9900;">synchronized(obj)</span>{
if(num>0){
try{
Thread.sleep(10);
}
catch(InterruptedException e){
System.out.println("中断异常");
}
System.out.println(Thread.currentThread().getName()+"......sale......"+num--);
}
}
}
}
}
public class Ti{
public static void main(String[] args){
Ticket t=new Ticket();
Thread t1=new Thread(t);
Thread t2=new Thread(t);
Thread t3=new Thread(t);
Thread t4=new Thread(t);
t1.start();
t2.start();
t3.start();
t4.start();
}
}
示例里开启了四个线程,同时执行同一个任务代码,这样就很容易出现线程安全问题,比如这里卖出0号票的情况,所以我们给任务代码加上同步锁,使得一个线程在执行任务代码时,其他线程处于临时阻塞状态,就不会进入任务代码执行了。这样就保证了线程安全。
同步的好处:解决了线程的安全问题。
同步的弊端:相对降低了效率,因为同步外的线程都会判断同步锁。
同步的前提:同步中必须有多个线程并使用同一把锁
下面的代码虽然用了同步代码块,但是将创建锁对象放在了run方法里面,也就是说每个线程进来都new了一个锁对象,每个线程都拥有了各自不同的锁,这样同步代码块就没有起到应有的作用,仍然会出现卖0号票的情况,相当于没有锁。
class Ticket implements Runnable{
private int num=100;
public void run(){
Object obj=new Object();
while(true){
synchronized(obj){
if(num>0){
try{
Thread.sleep(10);
}
catch(InterruptedException e){
System.out.println("中断异常");
}
System.out.println(Thread.currentThread().getName()+"......sale......"+num--);
}
}
}
}
}
public class Yi{
public static void main(String[] args){
Ticket t=new Ticket();
Thread t1=new Thread(t);
Thread t2=new Thread(t);
Thread t3=new Thread(t);
Thread t4=new Thread(t);
t1.start();
t2.start();
t3.start();
t4.start();
}
}
同步函数:就是给方法加上synchronized。
锁是this。
示例:
class Bank{
private int sum;
<span style="color:#ff6600;">public synchronized void add(int num)</span>{//同步函数
sum=sum+num;
try{
Thread.sleep(10);
}
catch(InterruptedException e){
System.out.println("中断异常");
}
System.out.println("sum="+sum);
}
}
class Cus implements Runnable{
private Bank b=new Bank();
public void run(){
for(int x=0;x<3;x++){
b.add(100);
}
}
}
public class Ni{
public static void main(String[] args){
Cus c=new Cus();
Thread t=new Thread(c);
Thread t1=new Thread(c);
t.start();
t1.start();
}
}
运行结果如下图
同步代码块和同步函数的区别:
同步代码块的锁是任意对象。
同步函数的锁是固定的this。
建议使用同步代码块。同步函数就是同步代码块在锁为this时的偷懒简写。
静态同步函数:就是在静态函数上加上synchronized。
锁是该函数所属字节码文件对象。可以用getClass方法获取,也可以用 当前类名.class 表示。
示例:
class Ticket implements Runnable{
private static int num=100;
boolean flag=true;
public void run(){
if(flag){
while(true){
synchronized(Ticket.class){ //synchronized(this.getClass()){
if(num>0){
try{
Thread.sleep(10);
}
catch(InterruptedException e){
System.out.println("中断异常");
}
System.out.println(Thread.currentThread().getName()+"......obj......"+num--);
}
}
}
}else{
while(true){
this.show();
}
}
}
<span style="color:#ff6600;">public static synchronized void show()</span>{ //静态同步函数
if(num>0){
try{
Thread.sleep(10);
}
catch(InterruptedException e){
System.out.println("中断异常");
}
System.out.println(Thread.currentThread().getName()+"......function......"+num--);
}
}
}
public class Ji{
public static void main(String[] args){
Ticket t=new Ticket();
Thread t1=new Thread(t);
Thread t2=new Thread(t);
t1.start();
try{
Thread.sleep(10);
}
catch(InterruptedException e){
System.out.println("中断异常");
}
t.flag=false;
t2.start();
}
}
运行结果如下图