1.复写run方法的目的在于,把要运行的代码放到run方法里面,也就是新的线程要跑什么内容
这也就是第一种多线程的方法,其主要的步骤如下:
- 继承Thread类
- 复写run方法
- 创建对象
- start
- 任何一个程序至少有一个线程就是主线程,主线程也是main方法的线程,这个线程是由jvm启动的,当我们自己创建新的线程的时候实际上是在主线程之外另开的新的线程和主线程并行工作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| class DemoRun extends Thread{ @Override public void run() { for (int i = 0; i < 60; i++) { System.out.println("thread---"+i); } } }
public class ThreadDemo { public static void main(String[] args) { DemoRun demoRun=new DemoRun(); demoRun.start(); for (int i = 0; i < 60; i++) { System.out.println("main---"+i); } } }
|
3.第一种创建线程的方式其实会有很大的局限性,例如说,我们说java是单继承的语言,那么也就会出现一个class继承了父类,无法在继承Thread类
而java却是多实现的,我们就可以继承runnable接口完成。但是注意,runnable接口并不是一个Thread类的对象,说白了他不是一个线程,那么我们
就不知道我们多线程到底要运行哪的代码,不明确run方法。所以我们就先建立Thread的对象,然后把runnable接口的对象传递给Thread类,这样一来Thread类就明确了
run方法的位置,也就是多线程要运行的代码的位置。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| class RunnableTest implements Runnable{ @Override public void run() { for (int i = 0; i < 60; i++) { System.out.println(Thread.currentThread().getName()+"-----"+i); } } }
public class RunnableDemo { public static void main(String[] args) { RunnableTest runnableTest=new RunnableTest(); Thread run=new Thread(runnableTest); Thread run1=new Thread(runnableTest); run.start(); run1.start(); } }
|
4.在说完多线程的创建以后最重要的就是线程的安全问题,主要就是共享变量的问题。例如上面的说到的实现runnable接口的时候,我们的属性就可以是共享变量
一般来说就是使用进程同步代码块来搞定,安全问题。当如具体我们要同步哪一个代码块就看我们那个块使用了共享
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| class TestDemo implements Runnable{ private int num; Object obj=new Object(); TestDemo(){ num=100; } @Override public void run() {
while (true){ synchronized (obj) { if (num > 0) { try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "=====" + num); num--; } } } } }
public class SyncDemo { public static void main(String[] args) { TestDemo testDemo=new TestDemo(); new Thread(testDemo).start(); new Thread(testDemo).start(); new Thread(testDemo).start(); } }
|
5.同步函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| class Bank{ public int sum; Bank(){ sum=0; }
public void add(int n){ sum+=n; } }
class TestDemo_01 implements Runnable{ private Bank bank=new Bank(); @Override public void run() { for (int i = 0; i < 3; i++) { synchronized (bank) { bank.add(100); try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(bank.sum); } } } }
public class SyncFunction { public static void main(String[] args) { TestDemo_01 testDemo_01=new TestDemo_01(); new Thread(testDemo_01).start(); new Thread(testDemo_01).start(); } }
|
6.如果在我们进行了代码同步以后,代码还挂了那就说明我们的代码没有满足两个前提:
7.线程通讯同步,所谓线程同步通讯就是,在多个线程同时对同一个资源进行操作的时候我们使用同步代码让他们同步,但是这样可能会造成两个线程各自执行到底
而非交替执行,为了交替执行我们使用同步,一个执行完了以后就睡眠唤醒另外一个,但是还是要注意这两个线程称一定要使用同一把锁,两个线程的代码都要同步
具体方法就是:
wait(),notify(),notifyAll()这几个函数都是使用在同步中的,因为他们需要对有监视器(锁)的对象进行操作
所以只有在同步中他们才有锁、
这些方法在操作线程的时候必须要标识他们所操作的锁,也就是说被某个锁同步的代码只能由此锁的wait,notify操作不可以对不同的锁的对象进行等待唤醒
由于锁是任意对象所以说这些方法都被定义在Object中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74
| class Resource{ private int count; public boolean flag; Resource(){ count=0; flag=true; }
public synchronized void in(){ if (flag) { try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("in===" + count++); flag=true; notify(); }
public synchronized void out(){ if (!flag){ try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("out------------"+count); flag=false; notify(); } }
class Producer implements Runnable{ private Resource resource;
public Producer(Resource resource) { this.resource = resource; }
@Override public void run() { while (true){ resource.in(); } } }
class Consumer implements Runnable{ private Resource resource;
public Consumer(Resource resource) { this.resource = resource; }
@Override public void run() { resource.out(); } }
public class ProducerAndConsumer { public static void main(String[] args) { Resource resource=new Resource(); Producer producer=new Producer(resource); Consumer consumer=new Consumer(resource); new Thread(producer).start(); new Thread(producer).start(); new Thread(consumer).start(); new Thread(consumer).start(); } }
|