Java multithreading Series 3-thread synchronization, java multithreading 3-Thread
If a resource is accessed by multiple threads at the same time, it may be damaged. This article introduces java thread synchronization to solve such problems.
Introduction Problems
A movie theater is currently releasing a new year's blockbuster with a total of 100 tickets, and it has three ticket sales windows. Please design a program to simulate the ticket sales at the cinema.
Method 1: Inherit the Thread class
Public class SellTicket extends Thread {// defines 100 tickets // private int tickets = 100; // to allow multiple Thread objects to share the 100 tickets, in fact, we should use static modification private static int tickets = 100; @ Override public void run () {// define 100 tickets // to simulate a continuous ticket while (true) {if (tickets> 0) {System. out. println (getName () + "selling" + (tickets --) + "tickets") ;}}}/** inherits the Thread class. */Public class SellTicketDemo {public static void main (String [] args) {// create three thread objects SellTicket st1 = new SellTicket (); SellTicket st2 = new SellTicket (); sellTicket st3 = new SellTicket (); // name the thread object st1.setName ("Window 1"); st2.setName ("window 2"); st3.setName ("window 3 "); // start the thread st1.start (); st2.start (); st3.start ();}}
Method 2: implement the Runnable interface
Public class SellTicket implements Runnable {// defines 100 tickets private int tickets = 100; @ Override public void run () {while (true) {if (tickets> 0) {System. out. println (Thread. currentThread (). getName () + "selling" + (tickets --) + "tickets ");}}}} /** implement the Runnable interface */public class SellTicketDemo {public static void main (String [] args) {// create a resource object SellTicket st = new SellTicket (); // create three Thread objects: Thread t1 = new Thread (st, "Window 1"); Thread t2 = new Thread (st, "window 2 "); thread t3 = new Thread (st, "window 3"); // start Thread t1.start (); t2.start (); t3.start ();}}
On the surface, there is no problem with the cinema ticket sales program. In real life, the network cannot be transmitted in real time during ticket sales, and there is always a delay. Therefore, after a ticket is sold, A delay of some time is required.
Change the ticket selling program that implements the interface method, with a latency of 100 milliseconds each time. The Code is as follows:
Public class SellTicket implements Runnable {// defines 100 tickets private int tickets = 100; @ Override public void run () {while (true) {// t1, t2, t3 three threads // This Time tickets = 1; if (tickets> 0) {// In order to simulate a more realistic scenario, let's take a break. try {Thread. sleep (100); // t1 comes in and rests, t2 comes in and rests, t3 comes in and rests,} catch (InterruptedException e) {e. printStackTrace ();} System. out. println (Thread. currentThread (). getName () + "selling" + (tickets --) + "tickets"); // window 1 is selling 1st tickets, tickets = 0 // window 2 is selling 0th tickets, tickets =-1 // window 3 is selling the-1 ticket, tickets =-2 }}}/** implement the Runnable interface */public class SellTicketDemo {public static void main (String [] args) {// create resource object SellTicket st = new SellTicket (); // create three Thread objects Thread t1 = new Thread (st, "Window 1 "); thread t2 = new Thread (st, "window 2"); Thread t3 = new Thread (st, "window 3"); // start Thread t1.start (); t2.start (); t3.start ();}}
Problem:
The same ticket appears multiple times
One CPU operation must be atomic.
A negative ticket is displayed.
Caused by randomness and latency
Basic ideas and methods for solving thread security problems
First, why? (It is also the Standard for us to determine whether there is a problem)
- Whether it is a multi-threaded Environment
- Shared data?
- Whether multiple statements are used to share data
How to solve the multi-thread security problem?
The basic idea is to leave the program in a safe environment.
Lock the code for operating the shared data with multiple statements so that only one thread can be executed at any time.
Solve thread security problems1 --Synchronous Code Block
Format: synchronized (object) {code to be synchronized ;}
The root cause of security problems solved by synchronization is on that object. This object is like a lock function.
Modify the above Code as follows:
Public class SellTicket implements Runnable {// defines 100 tickets private int tickets = 100; // creates a Lock Object private Object obj = new Object (); @ Override public void run () {while (true) {synchronized (obj) {if (tickets> 0) {try {Thread. sleep (100);} catch (InterruptedException e) {e. printStackTrace ();} System. out. println (Thread. currentThread (). getName () + "selling" + (tickets --) + "tickets") ;}}}/ ** Synchronous Code block :* Synchronized (object) {* code to be synchronized; *} ** A: What is the object? * You can create an object as needed. * B: What is the code to be synchronized? * Wrap up the code for multiple statements to operate on shared data. ** Note: * The root cause of synchronization can solve security problems lies in the object. This object is like a lock function. * Multiple threads must be the same lock. */Public class SellTicketDemo {public static void main (String [] args) {// create a resource object SellTicket st = new SellTicket (); // create three Thread objects: Thread t1 = new Thread (st, "Window 1"); Thread t2 = new Thread (st, "window 2 "); thread t3 = new Thread (st, "window 3"); // start Thread t1.start (); t2.start (); t3.start ();}}
Note: Synchronous Code blocks can be locked by any object.
Solve thread security problems2 --Synchronization Method
Is to add the synchronous keyword to the method.
1. Lock Object of the synchronization method: this
Public class SellTicket implements Runnable {private static int tickets = 100; private Object obj = new Object (); @ Override public void run () {while (true) {synchronized (this) {if (tickets> 0) {try {Thread. sleep (100);} catch (InterruptedException e) {e. printStackTrace ();} System. out. println (Thread. currentThread (). getName () + "selling" + (tickets --) + "tickets") ;}}} private synchronized void sellTicket () {if (tickets> 0) {try {Thread. sleep (100);} catch (InterruptedException e) {// TODO Auto-generated catch block e. printStackTrace ();} System. out. println (Thread. currentThread (). getName () + "selling" + (tickets --) + "tickets ");}}}
2. Static Method Lock Object: Class bytecode file object.
Public class SellTicket implements Runnable {private static int tickets = 100; private Object obj = new Object (); @ Override public void run () {while (true) {synchronized (SellTicket. class) {if (tickets> 0) {try {Thread. sleep (100);} catch (InterruptedException e) {e. printStackTrace ();} System. out. println (Thread. currentThread (). getName () + "selling" + (tickets --) + "tickets") ;}}} private static synchronized void sellTicket () {if (tickets> 0) {try {Thread. sleep (100);} catch (InterruptedException e) {// TODO Auto-generated catch block e. printStackTrace ();} System. out. println (Thread. currentThread (). getName () + "selling" + (tickets --) + "tickets ");}}}
Prerequisites for synchronization:
- Multiple Threads
- Multiple Threads use the same lock object.
Synchronization benefits: the emergence of synchronization solves the security problem of multithreading.
Synchronization disadvantages: when there are quite a few threads, every thread will judge the lock on synchronization, which is very resource-consuming and will virtually reduce the running efficiency of the program.
Solve thread security problems3 --Use of Lock
Although we can understand the Lock Object problem of the synchronization code block and method, we did not directly see where the lock was added and where the lock was released, to better express how to Lock and release the Lock, JDK 5 later provides a new Lock object Lock.
ReentrantLock (Java Platform SE 6)
A reentrant mutex lockLock
, It has and usessynchronized
The method and the implicit monitor lock accessed by the statement have the same basic behavior and semantics, but are more powerful.
Import java. util. concurrent. locks. lock; import java. util. concurrent. locks. reentrantLock; public class SellTicket implements Runnable {// defines the ticket private int tickets = 100; // defines the Lock Object private lock Lock = new ReentrantLock (); @ Override public void run () {while (true) {try {// lock. lock (); if (tickets> 0) {try {Thread. sleep (100);} catch (InterruptedException e) {e. printStackTrace ();} System. out. println (Thread. currentThread (). getName () + "selling" + (tickets --) + "tickets") ;}} finally {// release lock. unlock ();}}}}