天天看点

JAVA中利用 同步代码块 或 同步函数 解决线程的安全问题

线程的安全问题

当一个线程在执行操作共享数据的多条代码的过程中,其它线程参与运算,就会导致线程问题的产生

解决思路:

将多条操作共享数据的线程代码封装起来,当线程在执行这些代码的时候,
      其他线程不可以参与运算.
      必须要当前把这些代码执行完毕后,其它线程才可以参与运算.
           

同步代码

同步代码块的格式:
        synchronized(对象)
        {
            需要被同步的代码;
        }
           

例子:

class Ticket implements Runnable  //Ticket票
{
    private int num = 100;
    Object obj = new Object();
    public void run()
    {
        while(true)
        {
        //同步代码块
            synchronized(obj)
            {
                if (num > 0)
                {
                    
                    try
                    {
                        Thread.sleep(10);
                    }
                    catch (InterruptedException e)
                    {}

                     
                    System.out.println(Thread.currentThread().getName() + "......总票数剩余" + num--);
                }
            }
        }
    }
}
public class Demo{
    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();
    }
}
           

运行多次的结果:

(1)

JAVA中利用 同步代码块 或 同步函数 解决线程的安全问题

(2)

JAVA中利用 同步代码块 或 同步函数 解决线程的安全问题

同步的好处:解决了线程的安全问题

同步的弊端: 相对降低了效率....因为同步外的线程都会判断同步锁
		(因为如果有线程在同步里面,刚好CPU又突然给别的线程权限,但又进不去)
		(等到CPU重新给到在同步代码块里面的执行完毕出来后,才能给别的线程进去,所以降低了效率.)
	
   同步的前提: 同步中必须有多线程并使用同一个锁
           

.

.

.

.

同步函数

就是把同步代码块封装起来

例子:

public synchronized void show(){	//把同步代码块封装起来
        if (num > 0) {
            try {
                Thread.sleep(10);
            }
            catch (InterruptedException e) {

            }
            System.out.println(Thread.currentThread().getName() + "...function...总票数剩余" + num--);
        }
           
这里面的锁是对象是 this 也就是 它本身
           

也就说在上面的例子中我们可以不用Object 创建一个对象来当锁,而可以用自己的锁 this

可以写成这样

synchronized (this) {
    if (num > 0) {
      try {
		Thread.sleep(10);
      } catch (InterruptedException e) {
      }
    }
  System.out.println(Thread.currentThread().getName() + "....总票数剩余" + num--);
 }
           

同步函数使用的锁是this

同步函数和同步代码块的区别:

同步函数的锁是固定的this.

   同步代码块的锁是任意的对象
           

建议使用同步代码块

因为同步函数虽然简化,但是锁是唯一的…this

.

.

.

.

.

静态的同步函数

静态的同步函数使用的锁:

该函数所属字节码对象 可以用 getClass()方法获取

也可以用当前 类名.class 表示
           

例子:

可以

this.getClass()

//this当前的

Ticket是上面的类名 也可以

Ticket.class

synchronized(Ticket.class)
            {
                if (num > 0)
                {
                    try
                    {
                        Thread.sleep(10);
                    }
                    catch (InterruptedException e)
                    {}

                     
                    System.out.println(Thread.currentThread().getName() + "......总票数剩余" + num--);
                }
           

一般只要保证多个线程用同一个锁就行!!!