目次
カスタム オブジェクトをスレッド オブジェクト ロックとして使用する
クラスをスレッド オブジェクト ロックとして使用する
文法構造:
synchronized(XX.class){
//同步代码
}
また
synchronized public static void accessVal()
/**
* 定义销售员工类
*/
class Sale{
private String name;
public Sale(String name){
this.name = name;
}
/**
* 领取奖金
*/
synchronized public static void money(){
try {
System.out.println(Thread.currentThread().getName() + " 被领导表扬");
Thread.sleep(500);
System.out.println(Thread.currentThread().getName() + " 拿钱");
Thread.sleep(500);
System.out.println(Thread.currentThread().getName() + " 对公司表示感谢");
Thread.sleep(500);
System.out.println(Thread.currentThread().getName() + " 开开心心的拿钱走人");
} catch (InterruptedExceptione) {
e.printStackTrace();
}
}
}
class Programmer{
private String name;
public Programmer(String name){
this.name = name;
}
/**
* 打开电脑
*/
synchronized public void computer(){
try {
System.out.println(this.name + " 接通电源");
Thread.sleep(500);
System.out.println(this.name + " 按开机按键");
Thread.sleep(500);
System.out.println(this.name + " 系统启动中");
Thread.sleep(500);
System.out.println(this.name + " 系统启动成功");
} catch (InterruptedExceptione) {
e.printStackTrace();
}
}
/**
* 编码
*/
synchronized public void coding(){
try {
System.out.println(this.name + " 双击Idea");
Thread.sleep(500);
System.out.println(this.name + " Idea启动完毕");
Thread.sleep(500);
System.out.println(this.name + " 开开心心的写代码");
} catch (InterruptedExceptione) {
e.printStackTrace();
}
}
/**
* 去卫生间
*/
public void wc(){
synchronized ("suibian") {
try {
System.out.println(this.name + " 打开卫生间门");
Thread.sleep(500);
System.out.println(this.name + " 开始排泄");
Thread.sleep(500);
System.out.println(this.name + " 冲水");
Thread.sleep(500);System.out.println(this.name + " 离开卫生间");
} catch (InterruptedExceptione) {
e.printStackTrace();
}
}
}
/**
* 领取奖金
*/
public void money(){
synchronized (Programmer.class) {
try {
System.out.println(this.name + " 被领导表扬");
Thread.sleep(500);
System.out.println(this.name + " 拿钱");
Thread.sleep(500);
System.out.println(this.name + " 对公司表示感谢");
Thread.sleep(500);
System.out.println(this.name + " 开开心心的拿钱走人");
} catch (InterruptedExceptione) {
e.printStackTrace();
}
}
}
}
/**
* 打开电脑的工作线程
*/
class Working1 extends Thread{
private Programmer p;
public Working1(Programmer p){
this.p = p;
}
@Override
public void run() {
this.p.computer();
}
}
/**
* 编写代码的工作线程
*/
class Working2 extends Thread{
private Programmer p;
public Working2(Programmer p){
this.p = p;
}
@Override
public void run() {
this.p.coding();
}
}
/**
* 去卫生间的线程
*/
class WC extends Thread{
private Programmer p;
public WC(Programmer p){
this.p = p;
}
@Override
public void run() {
this.p.wc();
}
}
/**
* 程序员领取奖金
*/
class ProgrammerMoney extends Thread{
private Programmer p;
public ProgrammerMoney(Programmer p){
this.p = p;
}
@Override
public void run() {
this.p.money();
}
}
/**
* 销售部门领取奖金
*/
class SaleMoney extends Thread{
private Sale p;
public SaleMoneyThread(Sale p){
this.p = p;
}
@Override
public void run() {
this.p.money();
}
}
public class TestSyncThread {
public static void main(String[] args)
{
/* Programmer p = new Programmer("张三");
Programmer p1 = new Programmer("李四");
new ProgrammerMoney(p).start();
new ProgrammerMoney(p1).start();*/
Sale s = new Sale("张晓丽");
Sale s1 = new Sale("王晓红");
new SaleMoney(s).start();
new SaleMoney(s1).start();
}
}
カスタム オブジェクトをスレッド オブジェクト ロックとして使用する
文法構造:
synchronized(自定义对象){
//同步代码
}
/**
* 定义销售员工类
*/
class Sale{
private String name;
public Sale(String name){
this.name = name;
}
/**
* 领取奖金
*/
synchronized public static void money(){
try {
System.out.println(Thread.currentThread(). getName() + " 被领导表扬");
Thread.sleep(500);
System.out.println(Thread.currentThread().getName() + " 拿钱");
Thread.sleep(500);
System.out.println(Thread.currentThread().getName() + " 对公司表示感谢");
Thread.sleep(500);
System.out.println(Thread.currentThread().getName() + " 开开心心的拿钱走人");
} catch (InterruptedExceptione) {
e.printStackTrace();
}
}
}
class Programmer{
private String name;
public Programmer(String name){
this.name = name;
}
/**
* 打开电脑
*/
synchronized public void computer(){
try {
System.out.println(this.name + " 接通电源");
Thread.sleep(500);
System.out.println(this.name + " 按开机按键");
Thread.sleep(500);
System.out.println(this.name + " 系统启动中");
Thread.sleep(500);
System.out.println(this.name + " 系统启动成功");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
/**
* 编码
*/
synchronized public void coding(){
try {
System.out.println(this.name + " 双击Idea");
Thread.sleep(500);
System.out.println(this.name + " Idea启动完毕");
Thread.sleep(500);
System.out.println(this.name + " 开开心心的写代码");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
/**
* 去卫生间
*/
public void wc(){
synchronized ("suibian") {
try {
System.out.println(this.name + " 打开卫生间门");
Thread.sleep(500);
System.out.println(this.name + " 开始排泄");
Thread.sleep(500);
System.out.println(this.name + " 冲水");
Thread.sleep(500);
System.out.println(this.name + " 离开卫生间");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
/**
* 领取奖金
*/
public void money(){
synchronized (Programmer.class) {
try {
System.out.println(this.name + " 被领导表扬");
Thread.sleep(500);
System.out.println(this.name + " 拿钱");
Thread.sleep(500);
System.out.println(this.name + " 对公司表示感谢");
Thread.sleep(500);
System.out.println(this.name + " 开开心心的拿钱走人");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class Manager{
private String name;
public Manager(String name){
this.name = name;
}
public String getName(){
return this.name;
}
/**
* 敬酒
*/
public void cheers(String mName,String eName){
try {
System.out.println(mName + " 来到 " + eName + " 面前");
Thread.sleep(500);
System.out.println(eName + " 拿起酒杯");
Thread.sleep(500);
System.out.println(mName + " 和 " + eName + " 干杯");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
/**
* 打开电脑的工作线程
*/
class Working1 extends Thread{
private Programmer p;
public Working1(Programmer p){
this.p = p;
}
@Override
public void run() {
this.p.computer();
}
}
/**
* 编写代码的工作线程
*/
class Working2 extends Thread{
private Programmer p;
public Working2(Programmer p){
this.p = p;
}
@Override
public void run() {
this.p.coding();
}
}
/**
* 去卫生间的线程
*/
class WC extends Thread{
private Programmer p;
public WC(Programmer p){
this.p = p;
}
@Override
public void run() {
this.p.wc();
}
}
/**
* 程序员领取奖金
*/
class ProgrammerMoney extends Thread{
private Programmer p;
public ProgrammerMoney(Programmer p){
this.p = p;
}
@Override
public void run() {
this.p.money();
}
}
/**
* 销售部门领取奖金
*/
class SaleMoneyThread extends Thread{
private Sale p;
public SaleMoneyThread(Sale p){
this.p = p;
}
@Override
public void run() {
this.p.money();
}
}
/**
* 敬酒线程类
*/
class CheersThread extends Thread{
private Manager manager;
private String name;
public CheersThread(String name,Manager manager){
this.name = name;
this.manager = manager;
}
@Override
public void run() {
synchronized (this.manager) {
this.manager.cheers(this.manager.getName() , name);
}
}
}
public class TestSyncThread {
public static void main(String[] args)
{
Manager manager = new Manager("张三丰");
new CheersThread("张三",manager).start();
new CheersThread("李四",manager).start();
}
}
デッドロックと解決策
デッドロックの概念
「デッドロック」とは、複数のスレッドがそれぞれ共有リソースを占有し、他のスレッドが占有する互いのリソースが続行するのを待ち、その結果、2 つ以上のスレッドが互いのリソースを解放して実行を停止するのを待機することを指します。
同期ブロックが「2 つ以上のオブジェクトのロック」を同時に所有する必要がある場合、「デッドロック」の問題が発生する可能性があります。たとえば、「メイクアップ スレッド」が同期ブロックを実行するには、「ミラー オブジェクト」と「口紅オブジェクト」の両方が必要です。そして、実際の運用では、「小さな女の子のメイクアップスレッド」には「鏡オブジェクト」が、「大きな女の子のメイクアップスレッド」には「口紅オブジェクト」があり、メイクアップする前にお互いのリソースが解放されるのを待ちます。このようにして、2 つのスレッドは互いに待機し、実行を続行できない「デッドロック状態」を形成します。
デッドロックケースのデモンストレーション
/**
* 口红类
*/
class Lipstick{
}
/**
* 镜子类
*/
class Mirror{
}
/**
* 化妆线程类
*/
class Makeup extends Thread{
private int flag; //flag=0:拿着口红。 flag!=0:拿着镜子
private String girlName;
static Lipstick lipstick = new Lipstick();
static Mirror mirror = new Mirror();
public Makeup(int flag,String girlName){
this.flag = flag;
this.girlName = girlName;
}
@Override
public void run() {
this.doMakeup();
}
/**
* 开始化妆
*/
public void doMakeup(){
if(flag == 0){
synchronized (lipstick){
System.out.println(this.girlName+" 拿着口红");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (mirror){
System.out.println(this.girlName+" 拿着镜子");
}
}
}else{
synchronized (mirror){
System.out.println(this.girlName+" 拿着镜子");
try {
Thread.sleep(2000);
} catch(InterruptedException e) {
e.printStackTrace();
}
synchronized (lipstick){
System.out.println(this.girlName+" 拿着口红");
}
}
}
}
}
public class DeadLockThread {
public static void main(String[] args) {
new Makeup(0,"大丫").start();
new Makeup(1,"小丫").start();
}
}
デッドロック問題の解決策
デッドロックは、「同期ブロックが同時に複数のオブジェクト ロックを保持する必要がある」ことが原因で発生します。この問題を解決するための考え方は非常に単純です。同じコード ブロックが同時に 2 つのオブジェクト ロックを保持すべきではないということです。
/**
* 口红类
*/
class Lipstick{
}
/**
* 镜子类
*/
class Mirror{
}
/**
* 化妆线程类
*/
class Makeup extends Thread{
private int flag; //flag=0:拿着口红。 flag!=0:拿着镜子
private String girlName;
static Lipstick lipstick = new Lipstick();
static Mirror mirror = new Mirror();
public void setFlag(int flag) {
this.flag = flag;
}
public void setGirlName(String girlName)
{
this.girlName = girlName;
}
@Override
public void run() {
this.doMakeup();
}
/**
* 开始化妆
*/
public void doMakeup(){
if(flag == 0){
synchronized (lipstick){
System.out.println(this.girlName+" 拿着口红");
try {
Thread.sleep(1000);
} catch(InterruptedException e) {
e.printStackTrace();
}
}
synchronized (mirror){
System.out.println(this.girlName+" 拿着镜子");
}
}else{
synchronized (mirror){
System.out.println(this.girlName+" 拿着镜子");
try {
Thread.sleep(2000);
} catch(InterruptedException e) {
e.printStackTrace();
}
}
synchronized (lipstick){
System.out.println(this.girlName+" 拿着口红");
}
}
}
}
public class DeadLockThread {
public static void main(String[] args) {
Makeup makeup = new Makeup();
makeup.setFlag(0);
makeup.setGirlName("大丫");
Makeup makeup1 = new Makeup();
makeup1.setFlag(1);
makeup1.setGirlName("小丫");
makeup.start();
makeup1.start();
}
}
デッドロック問題の解決策
デッドロックは、「同期ブロックが同時に複数のオブジェクト ロックを保持する必要がある」ことが原因で発生します。この問題を解決するための考え方は非常に単純です。同じコード ブロックが同時に 2 つのオブジェクト ロックを保持すべきではないということです。
/**
* 口红类
*/
class Lipstick{
}
/**
* 镜子类
*/
class Mirror{
}
/**
* 化妆线程类
*/
class Makeup extends Thread{
private int flag; //flag = 0 :拿着口红,flag != 0 :拿着镜子
private String girlName;
static Lipstick lipstick = new Lipstick();
static Mirror mirror = new Mirror();
public Makeup(int flag,String girlName){
this.flag = flag;
this.girlName = girlName;
}
@Override
public void run() {
this.doMakeup();
}
/**
* 开始化妆
*/
public void doMakeup(){
if(this.flag == 0){
synchronized (lipstick){
System.out.println(this.girlName+" 拿着口红");
try {
Thread.sleep(1000);
} catch(InterruptedException e) {
e.printStackTrace();
}
}
synchronized (mirror){
System.out.println(this.girlName+" 拿着镜子");
}
}else{
synchronized (mirror){
System.out.println(this.girlName+" 拿着镜子");
try {
Thread.sleep(2000);
} catch(InterruptedException e) {
e.printStackTrace();
}
}
synchronized (lipstick){
System.out.println(this.girlName+" 拿着口红");
}
}
}
}
public class DeadLockThread {
public static void main(String[] args) {
new Makeup(0,"小丫").start();
new Makeup(1,"大丫").start();
}
}
スレッド同時連携(プロデューサー/コンシューマーモード)
マルチスレッド環境では、多くの場合、複数のスレッドの同時実行性と連携が必要になります。このとき、重要なマルチスレッド同時連携モデル「プロデューサー/コンシューマーモード」を理解する必要があります。
キャラクター紹介
プロデューサーとは何ですか?
プロデューサは、データの生成を担当するモジュールを指します (ここでのモジュールは、メソッド、オブジェクト、スレッド、プロセスなどです)。
Consumerとは?
コンシューマは、データの処理を担当するモジュールを指します (ここでのモジュールには、メソッド、オブジェクト、スレッド、プロセスが含まれます)。
バッファとは何ですか?
コンシューマはプロデューサのデータを直接使用することはできず、コンシューマの間には「バッファ」が存在します。プロデューサーは生成したデータを「バッファ」に置き、コンシューマは処理対象のデータを「バッファ」から取り出します。
バッファーは同時実行性を実現するための中核であり、バッファーの設定には次の 2 つの利点があります。
1 スレッドの同時連携を実現
バッファーを取得した後、プロデューサー スレッドはデータをバッファーに配置するだけで済み、コンシューマーの消費について気にする必要はありません。同様に、コンシューマーはバッファーからのデータを処理するだけでよく、プロデューサープロデュースのケース。このようにして、「プロデューサースレッド」と「コンシューマースレッド」の分離が論理的に実現され、プロデューサーとコンシューマーの結合が解放されます。
2 忙しさの偏りを解消し、効率を向上
プロデューサのデータ生成が遅い場合でも、バッファにはまだデータが存在するため、コンシューマの消費には影響しません。コンシューマのデータ処理が遅い場合でも、プロデューサはバッファにデータを配置し続けることができます。
プロデューサーとコンシューマーのパターンを実装する
バッファを作成する
/**
* 定义馒头类
*/
class ManTou{
private int id;
public ManTou(int id){
this.id = id;
}
public int getId(){
return this.id;
}
}
/**
* 定义缓冲区类
*/
class SyncStack{
//定义存放馒头的盒子
private ManTou[] mt = new ManTou[10];
//定义操作盒子的索引
private int index;
/**
* 放馒头
*/
public synchronized void push(ManTou manTou){
//判断盒子是否已满
while(this.index == this.mt.length){
try {
/**
* 语法:wait(),该方法必须要在 synchronized块中调用。
* wait执行后,线程会将持有的对象锁释放,并进入阻塞状态,
* 其他需要该对象锁的线程就可以继续运行了。
*/
this.wait();
} catch (InterruptedException e){
e.printStackTrace();
}
}
//唤醒取馒头的线程
/**
* 语法:该方法必须要在synchronized块中调用。
* 该方法会唤醒处于等待状态队列中的一个线程。
*/
this.notify();
this.mt[this.index] = manTou;
this.index++;
}
/**
* 取馒头
*/
public synchronized ManTou pop(){
while(this.index == 0){
try {
/**
* 语法:wait(),该方法必须要在synchronized块中调用。
* wait执行后,线程会将持有的对象锁释放,并进入阻塞状态,
* 其他需要该对象锁的线程就可以继续运行了。
*/
this.wait();
} catch (InterruptedException e)
{
e.printStackTrace();
}
}
this.notify();
this.index--;
return this.mt[this.index];
}
}
public class TestProduceThread {
public static void main(String[] args) {
}
}
プロデューサー・コンシューマー・スレッドを作成する
/**
* 定义馒头类
*/
class ManTou{
private int id;
public ManTou(int id){
this.id = id;
}
public int getId(){
return this.id;
}
}
/**
* 定义缓冲区类
*/
class SyncStack{
//定义存放馒头的盒子
private ManTou[] mt = new ManTou[10];
//定义操作盒子的索引
private int index;
/**
* 放馒头
*/
public synchronized void push(ManTou manTou){
//判断盒子是否已满
while(this.index == this.mt.length)
{
try {
/**
* 语法:wait(),该方法必须要在 synchronized块中调用。
* wait执行后,线程会将持有的对象锁释放,并进入阻塞状态,
* 其他需要该对象锁的线程就可以继续运行了。
*/
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//唤醒取馒头的线程
/**
* 语法:该方法必须要在synchronized块中调用。
* 该方法会唤醒处于等待状态队列中的一个线程。
*/
this.notify();
this.mt[this.index] = manTou;
this.index++;
}
/**
* 取馒头
*/
public synchronized ManTou pop(){
while(this.index == 0){
try {
/**
* 语法:wait(),该方法必须要在synchronized块中调用。
* wait执行后,线程会将持有的对象锁释放,并进入阻塞状态,
* 其他需要该对象锁的线程就可以继续运行了。
*/
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
this.notify();
this.index--;
return this.mt[this.index];
}
}
/**
* 定义生产者线程类
*/
class ShengChan extends Thread{
private SyncStack ss;
public ShengChan(SyncStack ss){
this.ss = ss;
}
@Override
public void run() {
for(int i=0;i<10;i++){
System.out.println("生产馒头:"+i);
ManTou manTou = new ManTou(i);
this.ss.push(manTou);
}
}
}
/**
* 定义消费者线程类
*/
class XiaoFei extends Thread{
private SyncStack ss;
public XiaoFei(SyncStack ss){
this.ss = ss;
}
@Override
public void run() {
for(int i=0;i<10;i++){
ManTou manTou = this.ss.pop();
System.out.println("消费馒头:"+i);
}
}
}
public class ProduceThread {
public static void main(String[] args)
{
SyncStack ss = new SyncStack();
new ShengChan(ss).start();
new XiaoFei(ss).start();
}
}
スレッドの同時実行と連携の概要
スレッド同時協力 (スレッド通信とも呼ばれます)
生産者消費者のパターン:
1 生産者と消費者は同じ資源を共有しており、生産者と消費者は互いに依存し、相互に条件付けされています。
2 生産者にとって、製品を生産する前に、消費者は待機状態に入らなければなりません。製品が製造された後は、消費者に消費について直ちに通知する必要があります。
3 消費者にとっては、消費後、消費が終了したことを生産者に通知し、消費のために新しい製品を生産する必要があります。4 プロデューサーコンシューマー問題では、同期だけでは十分ではありません。同期を使用すると、同じ共有リソースへの同時更新を防ぐことができ、同期を実現できますが、同期を使用して異なるスレッド間でのメッセージ パッシング (通信) を実現することはできません。
5 スレッドはメッセージ パッシング (通信) にどのような方法を使用しますか? 以下の概要を参照してください。
6 上記のメソッドは java.lang.Object クラスのメソッドです。
どちらも同期メソッドまたは同期コード ブロックでのみ使用でき、それ以外の場合は例外がスローされます。
OldLu は、このモードが実際の開発、特に「アーキテクチャ設計」で広く使用されることを示唆しました。初心者はこれだけで十分ですが、中級者や上級開発者になると必ずマスターする必要があります。