同步的局限性和静态同步在多线程中的使用
Java 的多线程特性是这个概念所围绕的特性,因为它允许并发执行程序的两个或多个部分,以最大限度地利用 CPU。这种程序的每一部分都称为一个线程。因此,线程是进程中的轻量级进程,众所周知,线程可以通过使用列出的两种机制创建:
- 扩展 Thread 类
- 实现 Runnable 接口
如果多个线程一次访问单个资源,则存在数据竞争或错误输出的可能性。让我们借助一个故事来理解这一点。让我们以多线程中的数据竞速为例,了解同步的局限性和静态同步的用途。让我们直接了解多线程中的数据竞赛。
执行:
Shubham 和 Sharmistha 正在计划约会并试图预订电影票。不幸的是,只有一张票可用。天才Java程序员 Shubham 知道一个技巧,并同时为他们俩同时要求一张票。天真的订票系统分配了 2 个线程并通过 book 方法传递它们。程序结束,两人各拿到一张票,剩下的票数为-1!
插图:多线程中的数据竞赛
Java
// Java program to show Data racing in multithreading.
// Helper class 1
class book {
int tickets = 1;
// method to book movie ticket
void book(int request, String name)
{
// logic to book ticket
if (tickets >= request) {
System.out.println(name + " booked " + request
+ " ticket.");
tickets = tickets - 1;
System.out.println("Tickets left: " + tickets);
}
else {
System.out.println("No tickets are available.");
}
}
}
// Helper class 2, extending Thread class.
// book method is called from this class using the object
// passed from main class.
class myThread extends Thread {
book obj;
int n;
String name;
myThread(book obj, String name, int n)
{
this.obj = obj;
this.n = n;
this.name = name;
}
// runs threads
public void run() { obj.book(n, name); }
}
// Driver class
public class GFG {
// Driver method
public static void main(String[] args)
{
// Creating object "obj" of book class and passing
// it to myThread class
book obj = new book();
myThread t1 = new myThread(obj, "Shubham", 1);
myThread t2 = new myThread(obj, "Sharmistha", 1);
// When a program calls the start() method, a new
// thread is created and then the run() method is
// executed.
// Starting threads created above
t1.start();
t2.start();
}
}
Java
// Java program to handle data racing due to
// multithreading using synchronization.
// Helper class 1
class book {
int tickets = 1;
// synchronized method to book movie ticket
synchronized void book(int request, String name)
{
// logic to book ticket
if (tickets >= request) {
System.out.println(name + " booked " + request
+ " ticket.");
tickets = tickets - 1;
System.out.println("Tickets left: " + tickets);
}
else {
System.out.println("No tickets are available.");
}
}
}
// Helper class 2, extending Thread class.
// book method is called from this class using the object
// passed from main class.
class myThread extends Thread {
book obj;
int n;
String name;
myThread(book obj, String name, int n)
{
this.obj = obj;
this.n = n;
this.name = name;
}
// runs threads
public void run() { obj.book(n, name); }
}
// Driver class
public class GFG {
// Driver method
public static void main(String[] args)
{
// Creating object "obj" of book class and passing
// it to myThread class
book obj = new book();
myThread t1 = new myThread(obj, "Shubham", 1);
myThread t2 = new myThread(obj, "Sharmistha", 1);
// When a program calls the start() method, a new
// thread is created and then the run() method is
// executed.
// Starting threads created above
t1.start();
t2.start();
}
}
Java
// Java program to illustrate limitations of
// synchronization.
// Helper class 1
class book {
int tickets = 1;
// synchronized method to book movie ticket
synchronized void book(int request, String name)
{
// logic to book ticket
if (tickets >= request) {
System.out.println(name + " booked " + request
+ " ticket.");
tickets = tickets - 1;
System.out.println("Tickets left: " + tickets);
}
else {
System.out.println("No tickets are available.");
}
}
}
// Helper class 2, extending Thread class.
// book method is called from this class using the object
// passed from main class.
class myThread extends Thread {
book obj;
int n;
String name;
myThread(book obj, String name, int n)
{
this.obj = obj;
this.n = n;
this.name = name;
}
// runs threads
public void run() { obj.book(n, name); }
}
// Driver class
public class GFG {
// Driver method
public static void main(String[] args)
{
// Creating multiple objects "obj" and "obj2" of
// book class and passing it to myThread class.
book obj = new book();
book obj2 = new book();
myThread t1 = new myThread(obj, "Shubham", 1);
myThread t2 = new myThread(obj2, "Sharmistha", 1);
// When a program calls the start() method, a new
// thread is created and then the run() method is
// executed.
// Starting threads created above
t1.start();
t2.start();
}
}
Java
// Java program to handle data racing using static
// synchronization.
// Helper class 1
class book {
static int tickets = 1;
// static synchronized method to book movie ticket
static synchronized void book(int request, String name)
{
// logic to book ticket
if (tickets >= request) {
System.out.println(name + " booked " + request
+ " ticket.");
tickets = tickets - 1;
System.out.println("Tickets left: " + tickets);
}
else {
System.out.println(
name + ", No tickets are available.");
}
}
}
// Helper class 2, extending Thread class.
// book method is called from this class using the object
// passed from main class.
class myThread extends Thread {
book obj;
int n;
String name;
myThread(book obj, String name, int n)
{
this.obj = obj;
this.n = n;
this.name = name;
}
// runs Threads
public void run() { obj.book(n, name); }
}
// Driver class
public class GFG {
// Driver method
public static void main(String[] args)
{
// Creating object "obj" of book class and passing
// it to myThread class
book obj = new book();
book obj2 = new book();
myThread t1 = new myThread(obj, "Shubham", 1);
myThread t2 = new myThread(obj2, "Sharmistha", 1);
// When a program calls the start() method, a new
// thread is created and then the run() method is
// executed.
// Starting threads created above
t1.start();
t2.start();
}
}
输出-
Shubham booked 1 ticket.
Sharmistha booked 1 ticket.
Tickets left: 0
Tickets left: -1
票数不能为负数。为了解决这个问题,工程师提出了同步概念。
同步——我们为对象提供一个锁并声明一个敏感区域(withdraw 方法)。一个对象可以有多个线程,但敏感区域一次只能被 1 个线程访问。
插图:使用同步处理由于多线程导致的数据竞争。
Java
// Java program to handle data racing due to
// multithreading using synchronization.
// Helper class 1
class book {
int tickets = 1;
// synchronized method to book movie ticket
synchronized void book(int request, String name)
{
// logic to book ticket
if (tickets >= request) {
System.out.println(name + " booked " + request
+ " ticket.");
tickets = tickets - 1;
System.out.println("Tickets left: " + tickets);
}
else {
System.out.println("No tickets are available.");
}
}
}
// Helper class 2, extending Thread class.
// book method is called from this class using the object
// passed from main class.
class myThread extends Thread {
book obj;
int n;
String name;
myThread(book obj, String name, int n)
{
this.obj = obj;
this.n = n;
this.name = name;
}
// runs threads
public void run() { obj.book(n, name); }
}
// Driver class
public class GFG {
// Driver method
public static void main(String[] args)
{
// Creating object "obj" of book class and passing
// it to myThread class
book obj = new book();
myThread t1 = new myThread(obj, "Shubham", 1);
myThread t2 = new myThread(obj, "Sharmistha", 1);
// When a program calls the start() method, a new
// thread is created and then the run() method is
// executed.
// Starting threads created above
t1.start();
t2.start();
}
}
输出-
Shubham booked 1 ticket.
Tickets left: 0
No tickets are available.
同步的限制:
如果 我们有来自 1 个对象的多个线程,而不是同步将处理数据竞争或错误输出。如果从多个对象分配多个线程会发生什么?这将再次导致不良输出或数据竞争。
插图:从多个对象分配多个线程时同步的缺点。
Java
// Java program to illustrate limitations of
// synchronization.
// Helper class 1
class book {
int tickets = 1;
// synchronized method to book movie ticket
synchronized void book(int request, String name)
{
// logic to book ticket
if (tickets >= request) {
System.out.println(name + " booked " + request
+ " ticket.");
tickets = tickets - 1;
System.out.println("Tickets left: " + tickets);
}
else {
System.out.println("No tickets are available.");
}
}
}
// Helper class 2, extending Thread class.
// book method is called from this class using the object
// passed from main class.
class myThread extends Thread {
book obj;
int n;
String name;
myThread(book obj, String name, int n)
{
this.obj = obj;
this.n = n;
this.name = name;
}
// runs threads
public void run() { obj.book(n, name); }
}
// Driver class
public class GFG {
// Driver method
public static void main(String[] args)
{
// Creating multiple objects "obj" and "obj2" of
// book class and passing it to myThread class.
book obj = new book();
book obj2 = new book();
myThread t1 = new myThread(obj, "Shubham", 1);
myThread t2 = new myThread(obj2, "Sharmistha", 1);
// When a program calls the start() method, a new
// thread is created and then the run() method is
// executed.
// Starting threads created above
t1.start();
t2.start();
}
}
输出-
Shubham booked 1 ticket.
Tickets left: 0
Sharmistha booked 1 ticket.
Tickets left: 0
我们只有一张票,但由于数据竞争,他们都成功预订了!为了解决这个问题,我们需要研究静态同步。
静态同步 -假设我们有 5 个对象。每个对象都有多个线程。现在敏感区域将一次被 5 个线程访问!
为了解决这个问题,工程师提出了静态同步的想法。我们为班级提供了一个锁。该类将一次选择 1 个对象。物体将依次选择 1 个线程并通过敏感区域。
插图:使用静态同步处理数据竞赛。
Java
// Java program to handle data racing using static
// synchronization.
// Helper class 1
class book {
static int tickets = 1;
// static synchronized method to book movie ticket
static synchronized void book(int request, String name)
{
// logic to book ticket
if (tickets >= request) {
System.out.println(name + " booked " + request
+ " ticket.");
tickets = tickets - 1;
System.out.println("Tickets left: " + tickets);
}
else {
System.out.println(
name + ", No tickets are available.");
}
}
}
// Helper class 2, extending Thread class.
// book method is called from this class using the object
// passed from main class.
class myThread extends Thread {
book obj;
int n;
String name;
myThread(book obj, String name, int n)
{
this.obj = obj;
this.n = n;
this.name = name;
}
// runs Threads
public void run() { obj.book(n, name); }
}
// Driver class
public class GFG {
// Driver method
public static void main(String[] args)
{
// Creating object "obj" of book class and passing
// it to myThread class
book obj = new book();
book obj2 = new book();
myThread t1 = new myThread(obj, "Shubham", 1);
myThread t2 = new myThread(obj2, "Sharmistha", 1);
// When a program calls the start() method, a new
// thread is created and then the run() method is
// executed.
// Starting threads created above
t1.start();
t2.start();
}
}
输出-
Shubham booked 1 ticket.
Tickets left: 0
Sharmistha, No tickets are available.
使用静态同步,我们准备了一个防止非法订票的系统。
结论-
- When we have multiple threads from a single object than we can use synchronization to lock the object to pass 1 thread at a time and prevent bad output.
- If multiple threads are assigned from multiple objects than we can not use synchronization. In such cases providing lock to the object will result in data racing. we need to use static synchronization and provide lock to the class. The class will select 1 object at a time. The object in turn will choose 1 thread and pass it to the sensitive area.