文章目录
1.线程
进程: 内存中运行的一个应用程序。
线程:进程中的执行流程
多线程: 一个进程中 由两个或两个以上这样的并发的执行流程。
2.线程状态
线程的生命周期:
1.新建
Thread 或 Thread子类
new Thread();
2.就绪
start()
等待cpu的调用执行
3.运行
cpu调用执行了此线程。
4.阻塞
运行的线程 由于 某种原因 暂停了 cpu的调用执行。
1)sleep: 等待 (时间毫秒long)
线程A 调用了sleep()方法 ,那么线程A就处于了 阻塞状态, 当等待的时间超时了,
那么线程A才能恢复到 就绪状态 ,等待cpu调用执行,一旦cpu调用执行了,那么就
处于 运行状态。
join: 让一些线程先执行完
当t1 调用 join()方法了,那么 t2线程需要等待 t1线程都执行完 ,才能恢复到 就绪状态,
t2在等待的过程中就是阻塞状态。
2)同步
排队
3) wait 等待
5.死亡
3.线程
1.主线程
最前 被 启动的线程 就是 主线程。
主线程的任务 在 main()中。
2.子线程
任务在 :run()中
方式一:继承Thread类
子线程的默认名称: Thread-0
class SubThread1 extends Thread{
// 给子线程起名字
SubThread1(String name){
super(name);
}
@Override
public void run() {
for(int i = 1; i <= 3; i++) {
System.out.println(Thread.currentThread().getName() + ": " + i);
}
}
}
public class TestSubThread1 {
public static void main(String[] args) {
//创建一个线程对象
SubThread1 t1 = new SubThread1("t1");
//启动一个线程
t1.start();
}
}
方式二:实现Runnable接口
class SubThread2 implements Runnable{
@Override
public void run() {
for(int i = 1; i <= 3; i++) {
System.out.println(Thread.currentThread().getName() + ":" + i);
}
}
}
public class TestSubThread2 {
public static void main(String[] args) {
//
SubThread2 st = new SubThread2();
//创建一个线程
Thread t = new Thread(st,"t1");
t.start();
}
}
方式三:实现Callable接口*
class SubThread3 implements Callable<Integer>{
@Override
public Integer call() throws Exception {
int sum = 0;
for(int i =1; i <= 3 ;i++) {
System.out.println(Thread.currentThread().getName()+":" + i);
sum += i;
}
return sum;
}
}
public class TestSubThread3 {
public static void main(String[] args) throws InterruptedException, ExecutionException {
SubThread3 sub = new SubThread3();
// 接收返回值
FutureTask<Integer> f = new FutureTask<>(sub);
//
Thread t = new Thread(f,"tt");
t.start();
//获得返回结果
System.out.println(f.get());
}
}
区别
1.继承Thread类 ,那么 这个类 就成为了一个线程类。
实现接口的其他两种方式 ,这个类本身不是线程类,需要借助Thread类创建线程。
2.实现接口的方式区别:
4.线程的优先级
1 - 10
1 - 最小的
10 - 最高的
设置优先级
// t1.setPriority(1);
// t2.setPriority(10);
t1.setPriority(Thread.MIN_PRIORITY);
t2.setPriority(Thread.MAX_PRIORITY);
5.方法
1.interrupt()线程中断
sleep()和join()
当t1 线程 被 t2线程中断了 ,那么 t1 线程 进入到异常处理。
class Thread1 implements Runnable{
public void run() {
for(int i = 1; i <= 10; i++) {
if( i == 5 ) {
try {
Thread.sleep( 1000);
} catch (InterruptedException e) {
System.out.println(Thread.currentThread().getName()+"进入到了异常处理");
}
}
System.out.println(Thread.currentThread().getName()+":" + i);
}
}
}
public class TestInterrupt {
public static void main(String[] args) {
Thread1 tr1 = new Thread1();
Thread t1 = new Thread(tr1,"t1");
t1.start();
t1.interrupt();// 中断t1
}
}
2.yield() 线程让步(了解)
Thread.yield()
class Thread2 implements Runnable{
public void run() {
for(int i = 1; i <= 10; i++) {
if( i == 5 && Thread.currentThread().getName().equals("t1") ) {
Thread.yield();//让步
}
System.out.println(Thread.currentThread().getName()+":" + i);
}
}
}
public class TestYield {
public static void main(String[] args) {
Thread2 tr2 = new Thread2();
Thread t1 = new Thread(tr2,"t1");
Thread t2 = new Thread(tr2,"t2");
t1.setPriority(1);
t2.setPriority(10);
t1.start();
t2.start();
}
}
6.线程同步
同步阻塞
1.获得锁
当线程 执行到 同步代码块 或 同步方法中的代码时,需要获得锁;
2.获得了锁
当线程A获得 锁成功,就可以执行同步代码块或同步方法中的代码了,
在执行的过程中,其他线程 是不能执行 此对象的同步代码块或同步方法中的代码,
但是 可以执行 其他 对象 的 同步代码块 或 同步方法的代码。
3.释放锁
1)同步代码块 或 同步方法的代码 正常执行完;
2)同步代码块 或 同步方法的代码 遇到了没有能处理的异常中断了程序;
3)同步代码块 或 同步方法的代码 return ,break; 结束了代码块或方法;
4)同步代码块 或 同步方法的代码 wait().
以上四种方式释放锁
法一
class Bank implements Runnable{
private int money = 0;
//存一次钱的方法 锁对象 this,synchronized在这里添加
synchronized public void setMoney() {
this.money += 100;
System.out.println(Thread.currentThread().getName()
+ "存了100,余额:" + this.money);
}
public void run() {
for(int i = 1; i <= 3; i++) {
this.setMoney();
}
}
}
public class TestBank {
public static void main(String[] args) {
Bank bank = new Bank();
Thread zhangsan = new Thread(bank,"张三");
Thread lisi = new Thread(bank,"李四");
zhangsan.start();
lisi.start();
}
}
法二
class Bank implements Runnable{
private int money = 0;
private int count = 0;
//存
public void setMoney() {
this.money += 100;
count ++;
System.out.println(Thread.currentThread()
.getName()+"剩"+money+","+count);
}
public void run() {
for (int i = 1; i <= 3; i++) {
//synchronized在这里添加
synchronized (this) {
this.setMoney();
}
}
}
}
7.ReentrantLock
法一
class Bank1 implements Runnable{
private int money = 0;
// 公平锁
ReentrantLock lock = new ReentrantLock();
//存一次钱的方法 锁对象 this
public void setMoney() {
try {
lock.lock();// 获得锁
this.money += 100;
System.out.println(Thread.currentThread().getName()
+ "存了100,余额:" + this.money);
}finally {
lock.unlock();// 释放锁
}
}
public void run() {
for(int i = 1; i <= 3; i++) {
this.setMoney();
}
}
}
public class TestLock {
public static void main(String[] args) {
Bank1 bank = new Bank1();
Thread zhangsan = new Thread(bank,"张三");
Thread lisi = new Thread(bank,"李四");
zhangsan.start();
lisi.start();
}
}
法二
class Bank implements Runnable{
private int money = 0;
private int count = 0;
ReentrantLock lock = new ReentrantLock();
//存
public void setMoney() {
lock.lock();
this.money += 100;
count ++;
System.out.println(Thread.currentThread()
.getName()+"剩"+money+","+count);
lock.unlock();
}
public void run() {
for (int i = 1; i <= 3; i++) {
this.setMoney();
}
}
}
synchronized 和 Lock的区别
1.synchronized 是一个关键字 使用简单;
Lock 需要创建对象 ,显示获得锁 和 显示 释放锁;
2.synchronized 没有 明显的 获得锁 或 释放锁;
Lock可以 显示的获得锁和释放锁;
3.Lock 提供了更多的方法。提供了更多的功能。
8.编写:多线程
class SubThread5 implements Runnable{
@Override
public void run() {
for(int i = 1; i <= 10; i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + ":" + i);
}
}
}
public class TestSubThread5_exam {
public static void main(String[] args) {
SubThread5 sub = new SubThread5();
new Thread(sub,"t1").start();
new Thread(sub,"t2").start();
}
}
9.注意:
1.Callable有返回值
2.在线程少时sy和lock一样,线程多的时候用lock可以提升性能