一、继承Thread类

package MultiPluThread.createThread;

/**
 * Created by IntelliJ IDEA.
 *
 * @Author : yuankai
 * @create 2024/7/11 21:22
 */
public class MyThread extends Thread{
    // 这个线程内的变量就是共享变量,这里不同的线程售出了相同的票
    private int ticket = 15;

    @Override
    public void run() {
        while(ticket >0) {
            System.out.println(this.getName() + "售出第" + ticket + "张票");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            ticket--;
            if(ticket < 0) {
                System.out.println("售票结束");
            }
        }
    }
}

二、实现Runnable接口

package MultiPluThread.createThread;

public class MyRunnable implements Runnable{
    private int ticket = 15;
    @Override
    public void run() {
        while(ticket >0) {
            System.out.println(Thread.currentThread().getName()+ "售出第" + ticket + "张票");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            ticket--;
            if(ticket < 0) {
                System.out.println("售票结束");
            }
        }
    }
}

三、实现Callable接口

package MultiPluThread.createThread;

import java.util.concurrent.Callable;

/**
 * Created by IntelliJ IDEA.
 *
 * @Author : yuankai
 * @create 2024/7/11 21:47
 */
public class MyCallable implements Callable<Integer> {
    // 这里的返回值与Callable接口的泛型对应
    @Override
    public Integer call() throws Exception {
        int result = 0;
        for(int i = 0; i < 15; i++) {
            result += i;
        }
        return result;
    }
}

四、Test测试类

package MultiPluThread.createThread;

import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;

/**
 * Created by IntelliJ IDEA.
 *
 * @Author : yuankai
 * @create 2024/7/11 21:23
 */
public class Test {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        // 方式一
        new MyThread().start();
        new MyThread().start();
        // 方式二
        MyRunnable mr = new MyRunnable();
        new Thread(mr).start();
        new Thread(mr).start();
        // 方式三
        MyCallable callable = new MyCallable();
        FutureTask<Integer> result1 = new FutureTask<>(callable);
        FutureTask<Integer> result2 = new FutureTask<>(callable);
        Thread thread1 = new Thread(result1);
        Thread thread2 = new Thread(result2);
        thread1.start();
        thread2.start();
        Integer intResult1 = result1.get();
        Integer intResult2 = result2.get();
        System.out.println(intResult1 + "--"  +intResult2);
    }


}

五、线程安全

1.任意运行一种方式,我们可以发现当多个线程同时处理变量ticket的时候,会出现同时出售的情况,为什么解决这个问题,我们使用了synchronized关键字,来让ticket变量只能同时被一个线程所处理

六、synchronized的使用方式

1.修饰this变量,即修饰当前对象,只对同一个runnable变量生效,多个Runnable不起作用。(如果是修饰Object,和this类似,则只有当一个线程结束对Object的访问时,才会允许其他线程访问)

①Runnable接口实现类

package MultiPluThread.createThread;

public class MyRunnable implements Runnable{
    private int ticket = 15;
    @Override
    public void run() {
        synchronized (this) {
            while (ticket > 0) {
                System.out.println(Thread.currentThread().getName() + "售出第" + ticket + "张票");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                ticket--;
                if (ticket < 0) {
                    System.out.println("售票结束");
                }
            }
        }
    }
}

②Test测试类

package MultiPluThread.createThread;

import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;

/**
 * Created by IntelliJ IDEA.
 *
 * @Author : yuankai
 * @create 2024/7/11 21:23
 */
public class Test {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        // 多线程不是指多次执行run方法,而是指我们可以创建多个线程来"同时"执行run里面的方法
        // 方式一
//        new MyThread().start();
//        new MyThread().start();
        // 方式二,多个MyRunnable,锁不会生效
        MyRunnable mr = new MyRunnable();
        MyRunnable mr2 = new MyRunnable();
        new Thread(mr).start();
        new Thread(mr2).start();
        // 方式三,callable能接受该线程的run方法的返回值和异常
//        MyCallable callable = new MyCallable();
//        FutureTask<Integer> result1 = new FutureTask<>(callable);
//        FutureTask<Integer> result2 = new FutureTask<>(callable);
//        Thread thread1 = new Thread(result1);
//        Thread thread2 = new Thread(result2);
//        thread1.start();
//        thread2.start();
//        Integer intResult1 = result1.get();
//        Integer intResult2 = result2.get();
//        System.out.println(intResult1 + "--"  +intResult2);
    }


}

③图解

2.修饰方法或代码块

①锁定对象是函数对象,当这个函数或代码块被线程A使用时,线程B访问该函数或代码块将被堵塞,直到线程A使用完毕

package MultiPluThread.createThread;

public class MyRunnable implements Runnable{
    private int ticket = 15;
    private Object lock;

    @Override
    public synchronized void run() {
            while (ticket > 0) {
                System.out.println(Thread.currentThread().getName() + "售出第" + ticket + "张票");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                ticket--;
                if (ticket < 0) {
                    System.out.println("售票结束");
                }
            }
        
    }
}

3.修饰静态方法和Class

①静态方法代码

package MultiPluThread.createThread;

public class MyRunnable implements Runnable{
    private static int ticket = 15;
    private Object lock;

    @Override
    public synchronized void run() {
        method();
    }

    public synchronized static void method() {
        while (ticket > 0) {
            System.out.println(Thread.currentThread().getName() + "售出第" + ticket + "张票");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            ticket--;
            if (ticket < 0) {
                System.out.println("售票结束");
            }
        }
    }
}

②Test测试类

package MultiPluThread.createThread;

import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;

/**
 * Created by IntelliJ IDEA.
 *
 * @Author : yuankai
 * @create 2024/7/11 21:23
 */
public class Test {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        // 多线程不是指多次执行run方法,而是指我们可以创建多个线程来"同时"执行run里面的方法
        // 方式一
//        new MyThread().start();
//        new MyThread().start();
        // 方式二,多个MyRunnable,但静态方法是类级别的,因此也会生效
        MyRunnable mr = new MyRunnable();
        MyRunnable mr2 = new MyRunnable();
        new Thread(mr).start();
        new Thread(mr2).start();
        // 方式三,callable能接受该线程的run方法的返回值和异常
//        MyCallable callable = new MyCallable();
//        FutureTask<Integer> result1 = new FutureTask<>(callable);
//        FutureTask<Integer> result2 = new FutureTask<>(callable);
//        Thread thread1 = new Thread(result1);
//        Thread thread2 = new Thread(result2);
//        thread1.start();
//        thread2.start();
//        Integer intResult1 = result1.get();
//        Integer intResult2 = result2.get();
//        System.out.println(intResult1 + "--"  +intResult2);
    }


}

③测试结果,当Thread0执行时,尽管他们是不同的Runnable实例,但是属于同一个类,因此线程B依然会阻塞。Class同理,对于一个类只有一个class文件,因此对于不同的Runnable实例,线程B依然会被锁所阻塞


原来是小袁呐
1 声望0 粉丝