1. 개념
1. 프로세스
1.1 프로세스: 각 프로세스 실행에는 실행 경로인 실행 순서가 있거나 제어 장치를 호출합니다.
1.2 스레드: 프로세스의 독립적인 제어 단위입니다. 스레드는 프로세스의 실행을 제어합니다.
1.3 Java VM의 예:
Java VM이 시작되면 java.exe 프로세스가 있습니다. 이 프로세스에는 Java 실행을 담당하는 스레드가 하나 이상 있습니다. 프로그램과 이 스레드에 의해 실행되는 코드는 메인 메소드에 존재하며 이 스레드를 메인 스레드라고 합니다. 확장: 실제로 jvm에 대해 자세히 설명합니다. JVM은 하나 이상의 스레드를 시작하며, 가비지 수집 메커니즘을 담당하는 스레드도 있습니다
2. 멀티스레딩의 중요성: 실행 효율성 향상
2. 멀티스레딩
생성 1. 멀티스레드를 생성하는 첫 번째 방법, Thread 클래스 상속
1.1 Thread를 상속받을 클래스 정의, run 메소드 오버라이드 Run에 사용자 정의 코드를 저장하는 Thread 클래스에서 스레드를 실행합니다
1.2 스레드의 시작 메서드 호출 이 메서드에는 스레드를 시작하고 실행 메서드를 호출하는 두 가지 기능이 있습니다
.1.3 여러 스레드를 실행할 때 실행 결과는 매번 동일합니다. 여러 스레드가 CPU의 실행 권한을 얻었으므로 CPU가 실행하는 사람이 누구인지는 명확하게 말하면 하나의 프로그램만 실행될 수 있습니다. 특정 순간. (멀티코어 제외) 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.1 Runnable 인터페이스를 구현하기 위한 클래스 정의
2.2 Runnable에서 run 메서드 재정의 인터페이스: 스레드 추가 실행할 코드는 run 메소드에 저장됩니다
2.3 Thread 클래스를 통해 스레드 객체를 생성합니다
2.4 Runnable 인터페이스의 하위 클래스 객체를 전달합니다. Thread 클래스의 생성자에 대한 매개변수
Runnable 인터페이스의 하위 클래스 객체를 Thread의 생성자에 전달해야 하는 이유: 사용자 정의 run 메소드가 속한 객체는 Runnable 인터페이스의 하위 클래스 객체이기 때문에, 따라서 스레드가 지정된 개체의 run 메서드를 실행하도록 하려면 run 메서드가 속한 개체를 명확히 해야 합니다
2.5 Thread 클래스의 start 메서드를 호출하여 스레드를 시작하고 호출합니다. Runnable 인터페이스 하위 클래스의 메소드
/* * 需求:简易买票程序,多个窗口同时卖票 */ 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(); } }
3. 구현 방법과 상속 방법은 무엇입니까?
3.1 구현 방법은 단일 상속의 한계를 피하는 것이 좋습니다. 스레드 정의 시 구현 메서드 사용
3.2 Thread 클래스 상속: 스레드 코드는 Thread 하위 클래스의 run 메서드에 저장됩니다
3.3. 인터페이스 하위 클래스의 run 메서드
4. 멀티스레딩 실행 및 시작의 특징
4.1 run 메서드를 재정의해야 하는 이유는 무엇입니까?:
Thread 클래스 이 클래스는 스레드가 실행할 코드를 저장하는 함수를 정의합니다. 저장 함수는 실행 메소드입니다. 즉, Thread 클래스의 실행 메소드는 실행될 코드를 저장하는 데 사용됩니다. 스레드
5. 멀티 스레드 실행 상태
스레드 생성-run---sleep()/wait()--freeze---notify()--- Wake up
thread-run 생성---stop()--die
thread-run 생성---CPU 실행 권한을 얻지 못함-일시적으로 정지
6. 객체 및 해당 이름
6.1. 스레드에는 0부터 시작하는 고유한 기본 이름이 있습니다.
6.2. static Thread currentThread(): 현재 스레드 객체를 가져옵니다
6.3. getName(): 스레드 이름 가져오기
6.4 스레드 이름 설정: setName() 또는 생성자 사용
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); } } }
3. 다중 스레드 보안 문제
1. 멀티스레딩의 보안 문제 이유:
1.1. 동일한 스레드에서 여러 문이 동작하여 데이터를 공유하는 경우 하나의 스레드는 여러 문 중 일부만 실행하고 완료되기 전에 다른 스레드가 실행됩니다. 참여하여 실행하면 공유 데이터 오류 발생
1.2. 해결 방법: 공유 데이터에 대해 작동하는 여러 명령문의 경우 실행 프로세스 중에 다른 스레드가 실행에 참여할 수 없습니다.
1.3.java는 동기화된 코드 블록인 멀티 스레드 보안 문제에 대한 전문적인 솔루션을 제공합니다.
Synchronized(객체) {동기화해야 하는 코드}, 객체는 자물쇠와 같습니다. 잠금 스레드는 동기화로 실행될 수 있습니다. 잠금을 보유하지 않은 스레드는 CPU 실행 권한을 획득하더라도 잠금을 획득하지 못하므로 진입할 수 없습니다.
2. 동기화 전제 조건:
2.1. 반드시 2개 이상의 스레드가 있어야 합니다
2.2. 여러 스레드가 동일한 잠금을 사용해야 합니다
2.3 멀티스레딩의 보안 문제를 해결한다는 장점이 있습니다
2.4 단점은 여러 스레드가 잠금을 결정해야 하므로 더 많은 리소스를 소비한다는 것
2.5.동기화 기능
동기화 기능을 정의하고 메소드에서 동기화로 수정
/* * 需求: * 银行有一个金库,有两个储户分别存300元,每次存100元,存3次 * 目的:该程序是否有安全问题,如果有,如何解决 * 如何找问题: * 1.明确哪些代码是多线程代码 * 2.明确共享数据 * 3.明确多线程代码中哪些语句是操作共享数据的 */ public class Bank { private int sum; Object obj = new Object(); //定义同步函数,在方法钱用synchronized修饰即可 public synchronized void add(int n) { //synchronized (obj) { sumsum = sum + n; try { Thread.sleep(10); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println("sum=" + sum); //} } } class Cus implements Runnable { private Bank b = new Bank(); public void run() { for (int x = 0; x < 3; x++) { b.add(100); } } } class BankDemo { public static void main(String[] args) { Cus c = new Cus(); Thread t1 = new Thread(c); Thread t2 = new Thread(c); t1.start(); t2.start(); } }
6. 동기화된 잠금
6.1 함수는 개체에 의해 호출되어야 하며, 함수는 자신이 속한 개체에 대한 참조를 가지므로 이것이 사용되는 잠금입니다. 동기화된 함수는 이것이다
6.2.정적 함수 잠금이 메모리에 정적으로 입력되는 클래스 객체
인 경우 메모리에는 이 클래스의 객체가 없지만 반드시 있어야 합니다. 클래스에 해당하는 바이트코드 파일 객체, 클래스 이름.class, 객체 유형은 Class
입니다. 6.3 정적 동기화 방법, 사용되는 잠금은 메소드가 있는 클래스의 바이트코드 파일 객체입니다. 위치, 클래스 이름.class
/* * 需求:简��买票程序,多个窗口同时卖票 */ 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(); } }
7. 멀티스레딩, 싱글톤 모드-lazy 스타일
懒汉式与饿汉式的区别:懒汉式能延迟实例的加载,如果多线程访问时,懒汉式会出现安全问题,可以使用同步来解决,用同步函数和同步代码都可以,但是比较低效,用双重判断的形式能解决低效的问题,加同步的时候使用的锁是该类锁属的字节码文件对象
/* * 单例模式 */ //饿汉式 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(); } }