学习线程 先了解 线程与进程之间的关系
线程:
(线程是cpu调度的最小单位)
我们可以说是进程中执行运算的最小单位。
进程:
(进程是资源分配的最小单位)
我们可以说是一段程序执行的过程,
如果还是不清楚2着的话可以打一个比喻 进程 相当于火车, 线程就是火车的没一个车厢.
-----------------------------------------------------------------------------------------------------------------------------------------------
创建线程
Java 提供了三种创建线程的方法:
1 实现Runnable 的接口
步骤 1.1 建立Runnable 对象
1.2 使用参数为Runnable 对象的构造方法创建Thread实例
1.3 调用start方法启动线程
一个小demo
package me;
public class Main{
public static void main(String[] args){
Thread thread = new Thread(new Task());
thread.start();
}
static class Task implements Runnable{
@Override
public void run() {
for (int i=0;i<5;i++){
System.out.println(i);
try {
Thread.sleep(1500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
这个就是创建了一个类Task实现Runnable , 最后创建Thread 然后关联类Task
2 继承Thread类
package me;
public class Th extends Thread{
public static void main(String[] args){
Test test = new Test();
test.start();
}
static class Test extends Thread{
@Override
public void run() {
for (int i=0;i<10;i++){
System.out.println(i);
try {
Thread.sleep(1500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
因为Test 继承了Thread 所以这里没有在new Thread,
3 通过 Callable 和 Future 创建线程。
package me;
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;
public class Main implements Callable {
public static void main(String[] args) {
Main main = new Main();
FutureTask futureTask = new FutureTask<>(main);
Thread thread = new Thread(futureTask);
thread.start();
}
@Override
public Integer call() throws Exception {
int i = 0;
for (; i < 5; i++) {
System.out.println(i);
Thread.sleep(1500);
}
return i;
}
}
线程的生命周期
这个出生就是创建状态, 就绪状态, 执行状态,等待状态,死亡状态,休眠,阻塞状态
有时候我们看别的地方说5中,6中7中, 其实是吧休眠和阻塞当做一种了, 这个自己心里知道就行,
不过各个状态还是需要知道
线程的操作方法
1 线程休眠
调用sleep()方法
例如Thread.sleep(2000) 等待2秒
2 线程加入
当某个线程使用join()方法加入到另一个线程时,另一个线程等待该线程执行完毕以后在继续执行
3 线程礼让
使用yield()方法
yield 方法是具有同样优先级的线程进入可执行状态的机会,
4 中断线程
以前使用stop 不过这个方法已经过时了
现在提倡使用在run()方法里面使用无线循环形式,然后使用一个布尔型标记控制循环停止
如果线程使用了sleep()或wait()方法进入就绪状态,可以使用Thread类中的interrupt()方法是线程离开run()方法,同时线程结束
会抛出异常,用户可以处理该异常时完成线程的中断业务处理
线程同步与异步
线程同步使用 Synchronized 关键字 ,
同步可以比喻成大家排队上公交, 异步就是一起上没有顺序
异步的一个demo
package me;
public class Main {
public static void main(String[] args) {
Main demo = new Main();
//创建2个线程
new Thread(){
@Override
public void run() {
while (true){
demo.setName("张三");
}
}
}.start();
new Thread(){
@Override
public void run() {
while (true){
demo.setName("李四");
}
}
}.start();
}
public void setName(String str){
for ( int i=0;i
并没有顺序
同步 demo
package me;
import com.sun.source.tree.SynchronizedTree;
public class Main {
public static void main(String[] args) {
Main demo = new Main();
//创建2个线程
new Thread(){
@Override
public void run() {
while (true){
demo.setName("张三");
}
}
}.start();
new Thread(){
@Override
public void run() {
while (true){
demo.setName("李四");
}
}
}.start();
}
public void setName(String str){
synchronized (this){
for ( int i=0;i
当然我们还可以使用lock()方法来实现同步效果
package me;
import com.sun.source.tree.SynchronizedTree;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class Main {
Lock lock = new ReentrantLock();
public static void main(String[] args) {
Main demo = new Main();
//创建2个线程
new Thread() {
@Override
public void run() {
while (true) {
demo.setName("张三");
}
}
}.start();
new Thread() {
@Override
public void run() {
while (true) {
demo.setName("李四");
}
}
}.start();
}
public void setName(String str) {
lock.lock();//加锁
try{
for (int i = 0; i < str.length(); i++) {
System.out.print(str.charAt(i));
}
System.out.println();
}finally {
lock.unlock();//解锁
}
}
}
使用lock 记得使用try 方法不然要发生异常了, 就没法解锁了 ,try 方法可以很好的处理
lock 是jdk 1.5之后出现的非常好用
线程死锁
有时候2个或者多个线程需要在几个共享对象上获取锁,可能会导致死锁
一般我们是使用synchronized不当的时候就是引起死锁
一个死锁的案例
public void add(int[] a1,int[]a2){
int value = 0;
int size = a1.length;
if (size == a2.length){
synchronized (a1){
synchronized (a2){
for (int i=0;i
避免死锁
尽量避免在同一把锁的代码中用到另一把锁资源,还尽量避免使用全局对象
我们也可以使用资源排序的技术 就是A和B , B必须获得A上的锁然后才能获取B上的锁,一旦A获取A上的锁线程B 必须等待A上的锁
总结下线程上使用的方法
.wait() //当前线程挂起
.notify()// 唤醒正在排队等待同步资源的线程中优先级最高者结束等待
.notifyAll()// 唤醒正在排队等待资源的所有线程结束
Thread.sleep(); //线程休眠
Thread.yield()//暂停当前线程的执行,让具有同样优先级的线程进入可执行状态的机会
.start() //线程开始