一、创建方法1:extends Thread

Step 1: 声明一个类,继承Thread类

Step 2: 在方法“Run()”中写需要运行的代码

step 3: 创建类的实例

step 4: 调用start()方法,运行线程。

二、创建方法2 implements Runnable

step 1: 声明一个类,implements Runnable接口

step 2: 在该类中重写run()方法

step 3: 使用new Thread(new <classname>)创建实例

step 4:调用.start()方法

区别:

1、extends Thread无法再继承其他类

2、extends Thread后,每次都会创建新实例,各个实例之间运行没有联系。
而implements runnable,每次仅仅是创建新线程,各个线程之间共享内存

三、同步锁synchronized

implements实现了内存共享。但是无法解决并发问题,比如:两个线程同时修改一段内存,可能只有一个修改是生效的。

package thread_test;

public class MyThread implements Runnable{
    public int i =0;
    public void run(){
        for (int j =0 ; j<10000;j++){
            this.i++;
        }
    }

    public static void main(String[] args) throws InterruptedException {
        MyThread test = new MyThread();
        Thread t1 = new Thread(test);
        Thread t2 = new Thread(test);
        t1.start();
        t2.start();
        t1.join();
        t2.join();
        System.out.println(test.i);
    }
}

输出结果是15872。本该执行了20000次i++,但有4千多次因为访问冲突而失效了。

同步锁就是用来解决这个问题。使用synchronized修饰的函数,仅会同时被一个线程访问。

package thread_test;

public class MyThread implements Runnable{
    public int i =0;
    synchronized  void increase() {
        this.i++;
    }
    public void run(){
        for (int j =0 ; j<10000;j++){
            this.increase();
        }
    }

    public static void main(String[] args) throws InterruptedException {
        MyThread test = new MyThread();
        Thread t1 = new Thread(test);
        Thread t2 = new Thread(test);
        t1.start();
        t2.start();
        t1.join();
        t2.join();
        System.out.println(test.i);
    }
}

得到的结果是20000