Javaでのマルチスレッドの概要

スレッドを理解するには、プロセスを理解する必要があります。
プロセスとは何ですか?プロセス:プログラムがプロセッサで実行されるときに発生するアクティビティはプロセスと呼ばれます。プロセスは実行中のプログラム、アクティブエンティティであり、プロセスは「自己完結型」実行中のプログラム、独自のアドレス空間を持つ簡単に言えば、私のコンピュータは、PPTやワード2つのプログラムを開いた場合、それは2つのプロセスと同等である。。
スレッド:スレッドは軽量プロセス、基本単位である
スレッドによって使用されますCPUは特定の1つのプロセスに属し、1つのプロセスには1つ以上のスレッドがあります。
複数のスレッドが同じプロセスリソースを共有しますマルチタスクに
は2つのタイプがあります
プロセスベース:コンピューターは複数のプロセスを同時に
実行しますスレッドベース:Aプロセスには複数のスレッドが含まれます
機能:
各プロセスは独自の独立したアドレススペースを割り当てる必要があります
プロセス間呼び出しはスレッド間通信よりも多くのオーバーヘッドを伴います
複数のスレッドは同じアドレススペースを共有し、同じプロセスを
一緒に共有できますスレッド間の切り替えは、プロセス間の切り替えよりもコストがかかります低
プロセスは重量があり、スレッドは軽量
JVMのスレッドです

  1. オペレーティングシステムの起動時に
    プロセスが作成されます(javac、java、javawなどのコマンド)JVM

  2. JVMプロセスには、メインメソッドとガベージコレクションスレッドの少なくとも2つのスレッドがあります。これらは
    メインスレッドと呼ばれます。他のスレッドを開始することもあります。最終的に実行を完了し、
    さまざまなシャットダウンおよびリリースアクションを実行する必要があり
    ます。Javaでは、スレッドが実装されます。3つの方法があります。
    (1)Threadクラスのサブクラスを宣言し、run()メソッドをオーバーライドします。

     public class SampleThread extends Thread {
     		public void run( ) {/* 覆盖该方法*/ }
     		 }
      }
    

(2)Runnableインターフェースを実装するクラスを宣言し、run()メソッドを実装します

		public class SampleThread implements Runnable{
    				public void run( ) {
    				/* 实现该方法*/
    				 }
    	}

(3)Callableインターフェイスを実装し、彼のcallメソッドを実装します。

import java.util.concurrent.Callable;

public class Thread<V> implements Callable<V>{

	public V call() throws Exception {
		// TODO Auto-generated method stub
		return null;
	}
}
Callable<V> oneCallable = new SomeCallable<V>();   
//由Callable<Integer>创建一个FutureTask<Integer>对象:   
FutureTask<V> oneTask = new FutureTask<V>(oneCallable);   
//注释:FutureTask<Integer>是一个包装器,它通过接受Callable<Integer>来创建,它同时实现了Future和Runnable接口。 
  //由FutureTask<Integer>创建一个Thread对象:   
Thread oneThread = new Thread(oneTask);   
oneThread.start();   
//至此,一个线程就创建完成了。

Threadクラスを直接継承する最初のメソッドは、runメソッドを直接書き直すこと、つまり自分自身をスレッドに変えることです。2番目のメソッドはスレッド自体ではなく、実行可能なインターフェイスを実装します。その中のrunメソッドには、空のスレッドの実行方法を指定する機能しかありません
。2番目の方法のコード例:
最初に2つのスレッドを定義します; MyT1とMyT2(次のコードを分離するために自分で3つのクラスを作成してください)

public class MyT1 extends Thread {
	@Override
	public void run() {
		for(int i = 0; i < 1000; i++) {
			System.out.println("aaaaa");
		}
	}
}
public class MyT2 extends Thread {
    	@Override
    	public void run() {
    		for(int i = 0; i < 1000; i++) {
    			System.out.println("bbbbb");
    		}
    	}
    }
public class Run {
	public static void main(String[] args) {
		System.out.println("main开始!");
		MyT1 t1 = new MyT1();
		MyT2 t2 = new MyT2();
		//设置线程优先级
		t1.setPriority(1);
		t2.setPriority(10);
		t1.start();
		t2.start();
		System.out.println("main结束!");
	}
}

2番目の方法:
最初に2つのスレッドを定義します; MyT1とMyT2(次のコードを分離するために自分で3つのクラスを作成してください)

public class MyT1 implements Runnable {
	@Override
	public void run() {
		try {
			for(int i = 0; i < 10; i++) {
				System.out.println("aaaaa");
				Thread.currentThread().sleep(1000);
			}
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}
//此处MyT2和MyT1采用不同的写法
public class MyT2 implements Runnable {
	private Thread t = null;
	public MyT2() {
		this.t = new Thread(this);
		this.t.start();
	}
	@Override
	public void run() {
		try {
			for(int i = 0; i < 10; i++) {
				System.out.println("bbbbb");
				Thread.currentThread().sleep(2000);
			}
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}
public class Run {
	public static void main(String[] args) {
		System.out.println("main开始!");
		//MyT1和MyT2的=run的方式也会有所不同
		Thread t1 = new Thread(new MyT1());
		t1.start();
		new MyT2();
		System.out.println("main结束!");
	}
}

スレッドの状態:
新しい状態(NEW):これまでに開始
されていないスレッドはこの状態
ですThread.start ()メソッドを呼び出さなかった新しく作成されたスレッドはこの状態です。実行可能:スレッドの状態実行可能なスレッド
。startメソッドを呼び出します。実行可能な状態のスレッドがJava仮想マシンで実行されていますが、プロセッサの
ロック状態(待機状態)(BLOCKED)などのオペレーティングシステム内の他のリソースを待機している可能性があります。ブロックされたスレッドのスレッド状態
ブロックされた状態のスレッドは、モニターロックが同期された
ブロック/メソッドに入るのを待っているか、Object.wait()を呼び出した後に再び同期されたブロック/メソッドに入るのを待っています
ロックされた状態はタイミングに分割されますロック(指定されたタイムロック)および不規則なロック(スリープメソッドの呼び出し)
終了状態(TERMINATED):終了したスレッドのスレッド状態。スレッドは実行を終了しました
2:スレッド内の
ここに画像の説明を挿入
ここに画像の説明を挿入
メソッド1.sleep()メソッド
現在実行中のスレッドに指定された時間内に実行を一時停止させますが、「ロックフラグ」は解放されません。推奨されません。sleep()は、現在のスレッドをブロッキング状態にし、指定された時間内に実行されません。
2.wait()メソッド
他のスレッドがオブジェクトのnotifyまたはnotifyAllメソッドを呼び出す前に、現在のスレッドが待機します。スレッドは保持している「ロックフラグ」を解放するため、他のスレッドがロックを取得する機会があります。現在のスレッドは、現在のオブジェクトロックを所有している必要があります。現在のスレッドがこのロックの所有者でない場合、IllegalMonitorStateExceptionがスローされます。
notifyまたはnotifyAllメソッドを使用して現在のオブジェクトロックをウェイクアップする待機中のスレッドも、同じオブジェクトロックを持っている必要があります。そうでない場合、IllegalMonitorStateExceptionがスローされます。waite()およびnotify()は、同期関数または同期ブロックで呼び出す必要があります。呼び出しが非同期関数または非同期ブロックで行われた場合、コンパイルして渡すことはできますが、実行時にIllegalMonitorStateExceptionが発生します。
3. yieldメソッド
は、現在実行中のスレッドオブジェクトを一時停止します。Yield()は、現在のスレッドを実行可能状態に戻すだけなので、yield()を実行するスレッドは、実行可能状態に入った直後に実行できます。Yield()は、同じ優先度またはより高い優先度のスレッドにのみ実行の機会を与えることができます。
4. joinメソッド
は、スレッドが終了するのを待ちます。joinメソッドを呼び出したスレッドが終了するのを待ってから、実行を続行します。例:t.join(); //主にtスレッドの終了を待機するために使用されます。そのような文がない場合、mainが実行され、予期しない結果が発生します。
3:スレッドの優先順位(CPUを先取りするスレッドの能力)
あなたが優先順位を設定しない場合、デフォルトは5で、Javaは1が最低、10が最高で、1〜10の優先順位を提供します。
設定します優先方法:

final void setPriority(int newp) //: 修改线程的当前优先级
final int getPriority() //: 返回线程的优先级

4:スレッドの同期
2つ以上のスレッドが同時にリソースにアクセスしようとする場合があります。たとえば、1つのスレッドがファイルからデータを読み取ろうとし、別のスレッドが同じファイル内のデータを変更しようとする場合があります。この場合、データ一貫性が失われる可能性があります。共有リソースが常に1つのスレッドによってのみ使用されるようにするには、「同期」を使用する必要があります。同期とは、1つのスレッドのみが同時に同じリソースにアクセスできることを意味します。 。
同期を完了する2つの方法:
(1)同期方法、

synchronized void methodA() { }

(2)同期ブロック

 synchronized(object) {
		//要同步的语句
}

同期の例:
最初に、3つの新しいクラスPrintMStudentを作成してPrintMを実行します

public class PrintM {
	public void print(String info) {
		System.out.print("[" + info);
		try {
			Thread.currentThread().sleep(1000);
			System.out.println("]");
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}

学生:

public class Student extends Thread {
	private String name = null;
	private PrintM pm = null;
	public Student() {
		// TODO Auto-generated constructor stub
	}
	public Student(String n, PrintM p) {
		this.name = n;
		this.pm = p;
	}
	@Override
	public void run() {
		synchronized(this.pm) {
			this.pm.print(this.name);
		}
	}
}

このメソッド(同期ブロック)に加えて、プリンターprintMを使用して物を印刷するため、printMのprintメソッドを同期ブロックキーワードsynchronizedに追加することもできます(つまり、同期メソッド)

 public class Run {
	public static void main(String[] args) {
		PrintM pm = new PrintM();
		Student s1 = new Student("rose", pm);
		Student s2 = new Student("jack", pm);
		Student s3 = new Student("peter", pm);	
		s1.start();
		s2.start();
		s3.start();
	}
}

同期メソッドを使用する場合?同期ブロック?
同期メソッドを使用することをお勧めする状況は1つだけですこのクラスは自分で作成され、このクラスのこのメソッドは常に同期され、同期ブロックは基本的に他のクラスで使用されます。 !効率を向上させる有益である状況で、
5:待機通知メカニズム(物事を行うために協力する複数のスレッドを許可する)で
のJava、スレッド間通信のみ2種類/運用、待機を(提供)と通知を覚ます((のみ通知スレッド)自分に近い)とのnotifyAll()(すべてのスレッドは、物事を行うには目を覚ますが、唯一の優先順位が最も高いが、それを行うことができ、およびスレッドの残りの部分はまだ待つ)理由:
これらの3つの方法が、同期でのみ使用することができますメソッド(これらのメソッドは、実装されたObjectクラスの最終メソッドとして使用されます)
サンプルコード:(本番(パン)番号、消費番号)
番号クラス:

public class Number {
	private int num = -1;
	private boolean numOk = false;
	/**
	 * 生成数字方法
	 * @param n 生成的数字
	 */
	public synchronized void putNum(int n) {
		if(numOk) {
			try {
				wait();
			} catch (InterruptedException e) {
				System.out.println("putNum()方法发生线程终断异常!");
				e.printStackTrace();
			}
		}
		this.num = n;
		this.numOk = true;
		System.out.println("生成数字:" + this.num);
//		try {
//			Thread.sleep(1000);
//		} catch (InterruptedException e) {
//			// TODO Auto-generated catch block
//			e.printStackTrace();
//		}
		notifyAll();
	}
	/**
	 * 得到数字方法
	 * @return 得到的数字
	 */
	public synchronized void getNum() {
		if(!numOk) {
			try {
				wait();
			} catch (InterruptedException e) {
				System.out.println("getNum()方法发生线程终断异常!");
				e.printStackTrace();
			}
		}
		System.out.println("得到数字:" + this.num);
		this.numOk = false;
//		try {
//			Thread.sleep(1000);
//		} catch (InterruptedException e) {
//			// TODO Auto-generated catch block
//			e.printStackTrace();
//		}
		notifyAll();
	}
}

クラスを生成する:

/**
 * 生成数字线程
 */
public class Produce implements Runnable {
	private int i = 0;
	private Number number = null;
	
	public Produce(Number n) {
		this.number = n;
		Thread t = new Thread(this, "produce");
		t.start();
	}
	public void run() {
		for(int j = 0; j < 10; j++) {
			this.number.putNum((i++) * 10);
		}
	}
}
Consume类:


  /**
 * 消费数字线程
 */
public class Consume implements Runnable {
	private Number number = null;
	
	public Consume(Number n) {
		this.number = n;
		Thread t = new Thread(this, "consume");
		t.start();
	}
	public void run() {
		for(int i = 0; i < 10; i++) {
			this.number.getNum();	
		}
	}
}

NumberRunクラス:

   public class NumberRun {

	public static void main(String[] args) {
		Number number = new Number();
		new Produce(number);
		new Consume(number);
	}
}

最後に、スレッドで作成されたガジェットを提供します:javaswing + threads、誰でも実行してプレイできます!!
3つのクラス:
BallPanelクラス:

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
/**
 * 绘制界类
 * @author IBMT40
 *
 */
public class BallPanel extends JFrame {
	private JPanel mainPanel = new JPanel();
	private JPanel operatePanel = new JPanel();
	
	public BallPanel() {
		Container c = this.getContentPane();
		c.setLayout(new BorderLayout());
		this.mainPanel.setBackground(Color.BLACK);
		c.add(this.mainPanel, BorderLayout.CENTER);
		JButton b1 = new JButton("开始");
		b1.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				Ball b = new Ball(mainPanel);
				b.start();
			}	
		});
		JButton b2 = new JButton("退出");
		b2.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				System.exit(0);
			}
		});
		this.operatePanel.add(b1);
		this.operatePanel.add(b2);
		c.add(this.operatePanel, BorderLayout.SOUTH);
		
		this.setSize(400, 400);
		this.setTitle("ball");
		this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		this.setVisible(true);
	}
}

ボールクラス:

import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JPanel;
/**
 * 绘制小球线程
 * @author IBMT40
 *
 */
public class Ball extends Thread {
	
	private JPanel mainPanel = null;
	private int x = 0;
	private int y = 0;
	private int dx = 5;
	private int dy = 5;
	private int width = 20;
	private int height = 20;
	
	public Ball(JPanel p) {
		this.mainPanel = p;
	}
	
	public void run() {
		init();
		while(true) {
			try {
				Thread.sleep(20);
				Graphics g = this.mainPanel.getGraphics();
				g.setColor(Color.WHITE);
				//g.setXORMode(this.mainPanel.getBackground());
				g.setXORMode(Color.BLACK);
				
				g.fillOval(this.x, this.y, this.width, this.height);
				x = x + dx;
				y = y + dy;
				if(x > this.mainPanel.getWidth() - this.width) {
					dx = -dx;
				}
				if(y > this.mainPanel.getHeight() - this.height) {
					dy = -dy;
				}
				if(x < 0) {
					x = 0;
					dx = -dx;
				}
				if(y < 0) {
					y = 0;
					dy = -dy;
				}
				g.fillOval(x, y, this.width, this.height);
				g.dispose();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
	private void init(){
		Graphics graphics = this.mainPanel.getGraphics();
		graphics.setColor(Color.WHITE);
		graphics.fillOval(x, y, this.width, this.height);
		graphics.dispose();
	}
}

BallRunクラス:

 /**
 * 主程序
 * @author IBMT40
 *
 */
public class BallRun {
	public static void main(String[] args) {
		new BallPanel();
	}
}

おすすめ

転載: blog.csdn.net/lq1759336950/article/details/97826074