Java多线程学习(2)

电脑杂谈  发布时间:2020-07-05 21:23:05  来源:网络整理

c++ 线程 安全_c++ 安全线程_线程安全问题代码

本文主要介绍Java多线程中的同步,即如何用Java语言编写线程安全程序,以及如何解决Java语言中与线程安全无关的问题. 是的,它是同步的.

一般来说,如何解决线程安全问题?

基本上,所有并发模式在解决线程安全问题时都使用“对关键资源的串行访问”解决方案,即一次只能有一个线程可以访问关键资源,也称为同步互斥锁.

通常来说,是在访问关键资源的代码前添加一个锁. 当访问关键资源时,将释放锁,以允许其他线程继续访问.

在Java中,有两种方法可以实现同步互斥访问: synced和Lock. 本文主要讨论同步的使用,稍后将介绍Lock的使用.

1. 简介

同步,我们称为锁定,主要用于锁定方法和代码块. 当一种方法或代码块使用同步时,则最多有一个线程在同一时间执行代码. 当多个线程访问同一对象的锁方法/代码块时,只有一个线程正在同时执行,其余线程必须等待当前线程执行后才能执行代码段. 但是,其余线程可以访问对象中的非锁定代码块.

同步化主要包括两种方法: 同步化方法,同步块化.

2. 同步方法

通过在方法声明中添加synced关键字来声明同步方法. 如:

public synchronized void getResult();

同步方法控制对类成员变量的访问. 如何避免对类成员变量的访问控制?我们知道该方法使用synced关键字表示该方法已被锁定. 当任何线程访问更改的方法时,它必须确定该方法中是否还有其他“独占”线程. 每个类实例都对应一个锁,每个同步方法都必须在执行该方法之前调用该方法的类实例的锁,否则将阻塞所属线程,并且一旦执行该方法,该锁就被独占,直到返回从方法. 释放后,被阻止的线程可以获得锁.

实际上,同步方法有缺陷. 如果我们将大型方法声明为同步方法,则将大大影响效率. 如果多个线程正在访问同步方法,则只有一个线程在同一时间执行该方法,而其他线程必须等待,但是如果该方法未使用同步,则所有线程都可以同时执行它,从而减少了执行时间. 总时间. 因此,如果我们知道一个方法不会被多个线程执行,或者没有资源共享的问题,那么我们就不需要使用synced关键字. 但是,如果您必须使用synced关键字,那么我们可以用synced代码块替换synced方法.

3. 同步块

同步代码块与同步方法具有相同的作用,不同之处在于它使关键部分尽可能短. 换句话说: 它仅保护所需的共享数据,而剩下的长代码块则保留此操作. 语法如下:

c++ 线程 安全_c++ 安全线程_线程安全问题代码

synchronized(object) {  
    //允许访问控制的代码  
}

如果我们需要以这种方式使用synced关键字,则必须将对象引用作为参数传递,通常是我们经常以此为参数.

synchronized (this) {
    //允许访问控制的代码 
}

4. 使用同步

同步代码块,修改后的代码成为同步语句块,其范围是调用此代码块的对象. 当使用synced关键字时,我们可以尽可能缩小代码段的范围. 将同步添加到段时,请勿将同步添加到整个方法. 这称为减小锁的粒度并提高代码的并发性.

同步方法,修改后的方法成为同步方法线程安全问题代码,其作用范围是整个方法,而功能对象是调用此方法的对象.

同步静态方法,修改静态静态方法,其作用域是整个静态方法,对象的作用是此类的所有对象.

Synchronized类,其作用域为sync(className.class),该类用Synchronized后面的括号括起来,作用对象是此类的所有对象.

synchronized(),()是锁定的对象,synced(this)仅锁定对象本身,不会锁定由相同类的不同对象调用的sync方法,并且sync(className.class)实现了该功能对于全局锁,此类调用此方法的所有对象均受该锁的影响,此外()还可以添加特定对象以实现对特定对象的锁定.

5. 同步注意事项

当两个并发线程访问同一对象中的同步代码块时,只能同时执行一个线程,而另一个线程则被阻塞. 在执行代码之前,必须等待当前线程执行此代码块. 片. 这两个线程是互斥的,因为当前对象在执行同步代码块时被锁定. 只有执行代码块后,才能释放对象锁定,并且下一个线程可以执行并锁定对象.

当一个线程访问对象的同步(此)同步代码块时,另一个线程仍可以访问对象中的非同步(此)同步代码块. (两个线程使用相同的对象)

当线程访问对象的同步代码块时,其他线程对该对象中所有其他同步代码块的访问将被阻止(与上述相同线程安全问题代码,两个线程使用同一对象).

以下是通过代码实现的:

1)当两个并发线程访问同一对象中的此同步(此)同步代码块时,一次只能执行一个线程. 另一个线程必须等待当前线程执行代码块,然后才能执行代码块.

线程安全问题代码_c++ 安全线程_c++ 线程 安全

复制代码

public class Thread1 implements Runnable {  
     public void run() {  
          synchronized(this) {  
               for (int i = 0; i < 5; i++) {  
                    System.out.println(Thread.currentThread().getName() + " synchronized loop " + i);  
               }  
          }  
     }  
     public static void main(String[] args) {  
          Thread1 t1 = new Thread1();  
          Thread ta = new Thread(t1, "A");  
          Thread tb = new Thread(t1, "B");  
          ta.start();  
          tb.start();  
     } 
}

复制代码

输出结果:

复制代码

A synchronized loop 0  
A synchronized loop 1  
A synchronized loop 2  
A synchronized loop 3  
A synchronized loop 4  
B synchronized loop 0  
B synchronized loop 1  
B synchronized loop 2  
B synchronized loop 3  
B synchronized loop 4

复制代码

2)但是,当一个线程访问对象的已同步代码块时,另一个线程仍可以访问对象中未同步的代码块.

复制代码

public class Thread2 {  
     public void m4t1() {  
          synchronized(this) {  
               int i = 5;  
               while( i-- > 0) {  
                    System.out.println(Thread.currentThread().getName() + " : " + i);  
                    try {  
                         Thread.sleep(500);  
                    } catch (InterruptedException ie) {  
                    }  
               }  
          }  
     }  
     public void m4t2() {  
          int i = 5;  
          while( i-- > 0) {  
               System.out.println(Thread.currentThread().getName() + " : " + i);  
               try {  
                    Thread.sleep(500);  
               } catch (InterruptedException ie) {  
               }  
          }  
     }  
     public static void main(String[] args) {  
          final Thread2 myt2 = new Thread2();  
          Thread t1 = new Thread(  new Runnable() {  public void run() {  myt2.m4t1();  }  }, "t1"  );  
          Thread t2 = new Thread(  new Runnable() {  public void run() { myt2.m4t2();   }  }, "t2"  );  
          t1.start();  
          t2.start();  
     } 
}

复制代码

输出结果:

复制代码

t1 : 4  
t2 : 4  
t1 : 3  
t2 : 3  
t1 : 2  
t2 : 2  
t1 : 1  
t2 : 1  
t1 : 0  
t2 : 0

复制代码

c++ 线程 安全_线程安全问题代码_c++ 安全线程

3)特别是,当一个线程访问一个对象的同步代码块时,其他线程对该对象中所有其他同步代码块的访问将被阻止.

复制代码

//修改Thread2.m4t2()方法:  
     public void m4t2() {  
          synchronized(this) {  
               int i = 5;  
               while( i-- > 0) {  
                    System.out.println(Thread.currentThread().getName() + " : " + i);  
                    try {  
                         Thread.sleep(500);  
                    } catch (InterruptedException ie) {  
                    }  
               }  
          }
     }

复制代码

输出结果:

复制代码

t1 : 4  
t1 : 3  
t1 : 2  
t1 : 1  
t1 : 0  
t2 : 4  
t2 : 3  
t2 : 2  
t2 : 1  
t2 : 0

复制代码

4)第三个示例也适用于其他同步代码块. 换句话说,当线程访问对象的同步(此)同步代码块时,它将获取对象的对象锁. 结果,其他线程对对象对象的所有同步代码部分的访问都被暂时阻止.

复制代码

//修改Thread2.m4t2()方法如下:
    public synchronized void m4t2() {  
         int i = 5;  
         while( i-- > 0) {  
              System.out.println(Thread.currentThread().getName() + " : " + i);  
              try {  
                   Thread.sleep(500);  
              } catch (InterruptedException ie) {  
              }  
         }  
    }


本文来自电脑杂谈,转载请注明本文网址:
https://www.pc-fly.com/a/jisuanjixue/article-269774-1.html

相关阅读
    发表评论  请自觉遵守互联网相关的政策法规,严禁发布、暴力、反动的言论

    热点图片
    拼命载入中...