1. 概念
1. プロセス
1.1 プロセス: 各プロセスの実行には、実行パス、または制御単位があります。
1.2 スレッド: プロセス内の独立した制御単位であり、プロセス内に少なくとも 1 つのスレッドが存在します。
1.3 Java VM の例:
Java VM が起動すると、Java プログラムの実行を担当するプロセス java.exe が存在し、このスレッドによって実行されるコードが存在します。 main メソッド内でこのスレッドをメインスレッドと呼びます。拡張: 実際、JVM は複数のスレッドとガベージ コレクション メカニズムを担当するスレッドを起動します。 2. マルチスレッドの重要性: 実行効率の向上。 1. マルチスレッドの作成 1つ目はThreadクラスを継承する方法です
1.1 Threadクラスを継承するクラスを定義し、Threadクラスのrunメソッドをオーバーライドしてカスタマイズしたコードをrunメソッドに格納してスレッドを実行させます。
1.2 スレッドの start メソッドを呼び出す このメソッドには、スレッドの開始と run メソッドの呼び出しの 2 つの機能があります。
1.3 複数のスレッドで実行する場合、複数のスレッドが CPU の実行権限を取得するため、実行結果は毎回異なります。そして、CPU が実行するプログラムは 1 つだけです。 (マルチコアを除く)、CPU は急速に切り替わり、同時に実行されているように見える効果を実現します。 CPU の実行能力を争うマルチスレッドの実行動作を視覚化できます。これはマルチスレッドのランダム性の特徴です。どれくらいの時間がかかるかについては、CPU が最終決定権を持っています。
public class Demo extends Thread{ public void run(){ for (int x = 0; x < 60; x++) { System.out.println(this.getName()+"demo run---"+x); } } public static void main(String[] args) { Demo d=new Demo();//创建一个线程 d.start();//开启线程,并执行该线程的run方法 d.run(); //仅仅是对象调用方法,而线程创建了但并没有运行 for (int x = 0; x < 60; x++) { System.out.println("Hello World---"+x); } } }
2 マルチスレッドを作成する 2 番目の方法の手順:
2.1 Runnable インターフェイスを実装するクラスを定義する
2.2 Runnable インターフェイスの run メソッドをオーバーライドする: スレッドによって実行されるコードを run に格納するメソッド
2.3. 渡す Thread クラスはスレッド オブジェクトを作成します
2.4. Runnable インターフェイスのサブクラス オブジェクトを実パラメータとして Thread クラスのコンストラクターに渡します
なぜ Runnable インターフェイスのサブクラス オブジェクトを渡す必要があるのですかThread のコンストラクター: カスタム run メソッドのため、これが属するオブジェクトは Runnable インターフェイスのサブクラス オブジェクトであるため、スレッドが指定されたオブジェクトの run メソッドを実行するには、実行先のオブジェクトを明確にする必要があります。メソッドが属します
2.5. Thread クラスの start メソッドを呼び出してスレッドを開始し、Runnable インターフェイスのサブクラスメソッド
を呼び出します。実装は、単一の制限を回避します。スレッドを定義するときに実装を使用することをお勧めします
3.2. Thread クラスを継承する: スレッドのコードはサブクラスの run メソッドに格納されます
3. Runnable を実装する: スレッドのコードはサブクラスの run メソッドに格納されます。インターフェース
4. マルチスレッド - run と start の特徴
4.1 run メソッドを上書きする理由:
Thread クラスはスレッドを記述するために、スレッドによって実行されるコードを格納する関数を定義します。 . storage 関数は run メソッドです。つまり、Thread クラスの run メソッドは、スレッドによって実行されるコードを保存するために使用されます
5. thread-run---sleep を作成します。 ()/wait()--freeze---notify()---wake up
Create thread-run---stop()-die
create Thread-run---CPU 実行権を取得しませんでした--一時的に凍結されています
6. スレッドオブジェクトとその名前を取得します
6.1. スレッドには独自のデフォルト名があり、番号は0から始まります
6.2.static Thread currentThread() :現在のスレッドオブジェクトを取得します
6.3 .getName(): スレッド名を取得します
6.4. スレッド名を設定します: setName() またはコンストラクターを使用します
3. マルチスレッドのセキュリティの問題
1.データを共有するために複数のステートメントが同じスレッド上で動作している場合、1 つのスレッドが複数のステートメントの一部のみを実行し、実行が完了する前に別のスレッドが実行に参加するため、共有データ エラーが発生します
解決策: 1.2 の場合。 1.3. Java は、コード ブロックを同期するという専門的なソリューションを提供します。 :
Synchronized (オブジェクト) {同期する必要があるコード}。 オブジェクトはロックのようなもので、ロックを保持していないスレッドは、CPU を取得しても同期して実行できます。 CPU 実行権。ロックが取得されていないためです
2. 同期の前提条件: 2 つ以上のスレッドが必要です
2.2. 利点は、次のとおりです。マルチスレッドのセキュリティ問題は解決されています
2.4. 欠点は、複数のスレッドがロックを決定する必要があり、より多くのリソースを消費することです
同期関数を定義し、メソッド内で synchronized を使用して変更します
/* * 需求:简易买票程序,多个窗口同时卖票 */ public class Ticket implements Runnable { private static int tick = 100; Object obj = new Object(); boolean flag=true; public void run() { if(flag){ while (true) { synchronized (Ticket.class) { if (tick > 0) { System.out.println(Thread.currentThread().getName() + "code:" + tick--); } } } }else{ while(true){ show(); } } } public static synchronized void show() { if (tick > 0) { System.out.println(Thread.currentThread().getName() + "show:" + tick--); } } } class ThisLockDemo { public static void main(String[] args) { Ticket t = new Ticket(); Thread t1 = new Thread(t); try { Thread.sleep(10); } catch (Exception e) { // TODO: handle exception } t.flag=false; Thread t2 = new Thread(t); //Thread t3 = new Thread(t); //Thread t4 = new Thread(t); t1.start(); t2.start(); //t3.start(); //t4.start(); } }
6. 同期ロック
6.1 関数はオブジェクトによって呼び出される必要があり、その場合、関数はそれが属するオブジェクトへの参照を持ちます。したがって、同期関数によって使用されるロックは this
6.2 です。静的関数のロックはクラスオブジェクトです
静的にメモリに入るとき、このクラスのオブジェクトはありませんが、このクラスに対応するバイトコードファイルオブジェクト、クラス名.classが存在する必要があります。オブジェクトの型はクラス
6.3. 静的同期メソッド、使用されるロックはメソッドが配置されているクラスのバイトコードファイルです。クラス名.class
public class Test extends Thread{ Test(String name){ super(name); } public void run(){ for (int x = 0; x < 60; x++) { System.out.println((Thread.currentThread()==this)+"..."+this.getName()+" run..."+x); } } } class ThreadTest{ public static void main(String[] args) { Test t1=new Test("one---"); Test t2=new Test("two+++"); t1.start(); t2.start(); t1.run(); t2.run(); for (int x = 0; x < 60; x++) { System.out.println("main----"+x); } } }
7. マルチスレッド、シングルトンモード遅延スタイル
。懒汉式与饿汉式的区别:懒汉式能延迟实例的加载,如果多线程访问时,懒汉式会出现安全问题,可以使用同步来解决,用同步函数和同步代码都可以,但是比较低效,用双重判断的形式能解决低效的问题,加同步的时候使用的锁是该类锁属的字节码文件对象
/* * 单例模式 */ //饿汉式 public class Single { private static final Single s=new Single(); private Single(){} public static Single getInstance(){ return s; } } //懒汉式 class Single2{ private static Single2 s2=null; private Single2(){} public static Single2 getInstance(){ if(s2==null){ synchronized(Single2.class){ if(s2==null){ s2=new Single2(); } } } return s2; } } class SingleDemo{ public static void main(String[] args) { System.out.println("Hello World"); } }
8.多线程-死锁
同步中嵌套同步会出现死锁
/* * 需求:简易买票程序,多个窗口同时卖票 */ public class DeadTest implements Runnable { private boolean flag; DeadTest(boolean flag) { this.flag = flag; } public void run() { if (flag) { synchronized(MyLock.locka){ System.out.println("if locka"); synchronized(MyLock.lockb){ System.out.println("if lockb"); } } } else { synchronized(MyLock.lockb){ System.out.println("else lockb"); synchronized(MyLock.locka){ System.out.println("else locka"); } } } } } class MyLock{ static Object locka=new Object(); static Object lockb=new Object(); } class DeadLockDemo { public static void main(String[] args) { Thread t1 = new Thread(new DeadTest(true)); Thread t2 = new Thread(new DeadTest(false)); t1.start(); t2.start(); } }