1 创建多线程
创建多线程一共有两种方式。一个是继承Thread类,另一个是实现Runable接口。其原理是一样的,本质上都是实现了Runable接口。因为Thread类就是实现了Runable接口。
1 实现Runable接口
1 2 3 4 5 6
| public class thread1 implements Runnable{ @Override public void run() { } }
|
2 继承Thread类
1 2 3 4 5 6
| public class thread1 extends Thread{ @Override public void run() { } }
|
2 启动线程
看下面,分别为两种不同创建线程方式的启动方法。可以看出在主方法中,最好都用了start方法启动了该线程。但是线程对象的创建方式却不同,Runable接口的是向Thread中注入了参数也就是下面的类t,而Thread类却直接创建了对象t。这是因为,Thread类已经实现了Runable接口,其实本质都是实现了Runable接口。
为啥线程开启不是用run方法,而是start方法呢?这是因为,run方法其实就是一个定义在Runab接口的普通方法,如果直接调用run方法,就不能直接开启线程,直接在main方法的主线程中执行。start方法其本质是调用了底层start0方法来开启线程。
1 Runable
1 2 3 4 5 6 7 8 9 10 11 12 13
| public class thread { public static void main(String[] args) { t t = new t(); Thread thread = new Thread(t); thread.start(); } } class t implements Runnable{ @Override public void run() { } }
|
2 Thread
1 2 3 4 5 6 7 8 9 10 11 12
| public class thread { public static void main(String[] args) { t t = new t(); t.start(); } } class t extends Thread{ @Override public void run() { } }
|
3 小案例
在银行中存放了10000元。有三个人分别取出里面的钱,一次取五百直到取完为止。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| public class thread { public static void main(String[] args) { t t = new t(); Thread thread1 = new Thread(t); Thread thread2 = new Thread(t); Thread thread3 = new Thread(t); thread1.start(); thread2.start(); thread3.start(); } } class t implements Runnable{ private static int money = 10000; @Override public void run() { while (money >= 0){ money = money-500; System.out.println(Thread.currentThread().getName() + "取走500还剩" + money ); } } }
|
但是在运行的结果中,我们看到有些顺序反了,按理说不应该出现啊。而且还出现了,银行余额为负数,这不应该啊。其实这就是线程不安全,多个线程同时访问一个资源造成的。在后面我们会解决他的。
![img]()
4 线程常用方法
1 线程名字
主线程的名字为main,后面的线程命为Thread-0,Thread-1…..
获取线程名字
1 2 3
| public final String getName() { return name; }
|
设置线程名字
1 2 3 4 5 6 7 8 9 10
| public final synchronized void setName(String name) { checkAccess(); if (name == null) { throw new NullPointerException("name cannot be null"); } this.name = name; if (threadStatus != 0) { setNativeName(name); } }
|
2 线程优先级
线程的默认优先级为5,最高为10,最低为1。
![img]()
获取当前优先级
1 2 3
| public final int getPriority() { return priority; }
|
设置优先级
1 2 3 4 5 6 7 8 9 10 11 12 13
| public final void setPriority(int newPriority) { ThreadGroup g; checkAccess(); if (newPriority > MAX_PRIORITY || newPriority < MIN_PRIORITY) { throw new IllegalArgumentException(); } if((g = getThreadGroup()) != null) { if (newPriority > g.getMaxPriority()) { newPriority = g.getMaxPriority(); } setPriority0(priority = newPriority); } }
|
3 其他
sleep(long n)
让线程休眠,单位为毫秒
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| public static void sleep(long millis, int nanos) throws InterruptedException { if (millis < 0) { throw new IllegalArgumentException("timeout value is negative"); } if (nanos < 0 || nanos > 999999) { throw new IllegalArgumentException( "nanosecond timeout value out of range"); } if (nanos >= 500000 || (nanos != 0 && millis == 0)) { millis++; } sleep(millis); }
|
join()
让当前线程立刻执行,直到执行完毕才能执行其他线程。
1 2 3
| public final void join() throws InterruptedException { join(0); }
|
yield()
让出当前线程的cpu,当时不一定让出。
1
| public static native void yield();
|
5 守护线程
守护线程是指为其他线程服务的线程。在JVM中,所有非守护线程都执行完毕后,无论有没有守护线程,虚拟机都会自动退出。因此JVM退出时,不必关心守护线程是否已结束。最经典的就是java的垃圾回收线程。
设置守护线程一定得在开起线程之前。
1 2 3
| Thread t = new Thread(t); t.setDaemon(true); t.start();
|
6 线程的六种状态
状态 |
解释 |
NEW |
尚未启动的线程状态,即线程创建,还未调用start方法 |
RUNNABLE |
就绪状态(调用start,等待调度)+正在运行 |
WAITING |
等待状态的线程正在等待另一线程执行特定的操作(如notify) |
TIME_WAITING |
具有指定等待时间的等待状态 |
BLOCKED |
等待监视器锁时,陷入阻塞状态 |
TERMINATED |
线程完成执行,终止状态 |
下面为图示
![img]()
其中RUNABLE状态又分为就绪状态和运行状态,所有有的书本上说线程有七种状态。
线程的主要路径为new—->runnable—>terminated;而其他的三个状态都是在围绕着runnable。
7 synchronized
线程同步机制是一套用于协调线程间的数据访问及活动的机制,该机制用于保障线程安全以及实现这些线程的共同目标
synchronized便常用于线程同步。有两种用法
修饰部分代码
修饰一个代码块,被修饰的代码块称为同步语句块,其作用的范围是大括号{}括起来的代码,作用的对象是调用这个代码块的对象;
1 2 3
| synchronized (object o) { }
|
修饰一个方法
- 修饰一个方法,被修饰的方法称为同步方法,其作用的范围是整个方法,作用的对象是调用这个方法的对象;
- 修改一个静态的方法,其作用的范围是整个静态方法,作用的对象是这个类的所有对象;
1 2 3 4
| public synchronized void method() { }
|
- 无论synchronized关键字加在方法上还是对象上,如果它作用的对象是非静态的,则它取得的锁是对象;如果synchronized作用的对象是一个静态方法或一个类,则它取得的锁是对类,该类所有的对象同一把锁。
- 每个对象只有一个锁(lock)与之相关联,谁拿到这个锁谁就可以运行它所控制的那段代码。
- 实现同步是要很大的系统开销作为代价的,甚至可能造成死锁,所以尽量避免无谓的同步控制
8 案例完善
只需要要上把锁就行
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
| public class thread { public static void main(String[] args) { t t = new t(); Thread thread1 = new Thread(t); Thread thread2 = new Thread(t); Thread thread3 = new Thread(t); thread1.start(); thread2.start(); thread3.start();
System.out.println(thread1.getState()); System.out.println(thread2.getState()); System.out.println(thread3.getState()); } }
class t implements Runnable { private static int money = 10000; private Object o = new Object();
@Override public void run() { synchronized (o) { while (money > 0) { money = money - 500; try { Thread.sleep(1000); } catch (InterruptedException e) { throw new RuntimeException(e); } System.out.println(Thread.currentThread().getName() + "取走500还剩" + money); } } } }
|
如果有什么,可以通过下面的邮箱和我联系!!!
![img]()