一.进程,线程
1.什么是进程,线程
进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。进程是线程的容器。程序是指令、数据及其组织形式的描述,进程是程序的实体。
线程(Thread)是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。
2.怎么创建线程
2.1 继承Thread类
/**
* 创建线程一:继承Thread类,重写run方法
*/
public class CreateThreadOne extends Thread{
@Override
public void run() {
for (int i = 0; i < 2000; i++) {
System.out.println("这是子线程=========="+i);
}
}
public static void main(String[] args) {
//创建线程
CreateThreadOne createThreadOne = new CreateThreadOne();
/**
* createThreadOne.run() :先执行run()方法的内容然后返回到主线程执行,同步执行
* createThreadOne.start():异步执行
*/
//createThreadOne.run();
createThreadOne.start();
for (int i = 0; i < 2000; i++) {
System.out.println("这是主线程"+i);
}
}
}
2.2 实现Runnable接口
public class CreateThreadTwo implements Runnable{
@Override
public void run() {
for (int i = 0; i < 1000; i++) {
System.out.println("这是子线程=========="+i);
}
}
public static void main(String[] args) {
CreateThreadTwo createThreadTwo = new CreateThreadTwo();
// createThreadTwo.run();
new Thread(createThreadTwo).start();
for (int i = 0; i < 1000; i++) {
System.out.println("这是主线程"+i);
}
}
}
2.3 实现Callable接口,重写call方法
public class CreateThreadThree implements Callable<Boolean> {
@Override
public Boolean call() throws Exception {
for (int i = 0; i < 200; i++) {
System.out.println("ThreadName:"+Thread.currentThread().getName()+",i="+i);
}
return true;
}
public static void main(String[] args) {
CreateThreadThree ctt1 = new CreateThreadThree();
CreateThreadThree ctt2 = new CreateThreadThree();
CreateThreadThree ctt3 = new CreateThreadThree();
//1.创建服务
ExecutorService executorService = Executors.newFixedThreadPool(3);
//2.提交执行
Future<Boolean> future1 = executorService.submit(ctt1);
Future<Boolean> future2 = executorService.submit(ctt2);
Future<Boolean> future3 = executorService.submit(ctt3);
//3.获取结果
try {
Boolean result1 = future1.get();
Boolean result2 = future2.get();
Boolean result3 = future3.get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
//4.关闭服务
executorService.shutdownNow();
}
}
3.Lambda表达式
3.1函数式接口:一个接口中只有一个抽象方法的接口叫函数式接口
可以通过Lambda表达式来创建接口的对象
四.线程的状态
4.1 线程的五大状态
4.2 线程的停止,使用标志位停止线程
/**
* jdk不推荐使用stop方法
* 使用标志位来使线程停止
*/
public class TestStop implements Runnable{
/**
* 设置标志位,当flag=false时线程停止
*/
private boolean flag = true;
@Override
public void run() {
int i = 0;
while (flag){
System.out.println(Thread.currentThread().getName()+",i="+i+++"============");
}
}
//结束线程的方法
public void stop(){
this.flag = false;
}
public static void main(String[] args) {
TestStop testStop = new TestStop();
new Thread(testStop,"testStop").start();
for (int i = 0; i < 200; i++) {
if (i==190){
testStop.stop();
}
System.out.println("main,i="+i);
}
}
}
4.3 线程休眠_sleep作用
模拟网络延迟(放大问题的发生性),倒计时
每一个对象都有一把锁,sleep不会释放锁
4.4线程礼让_yield作用
public class TestYield implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+",start");
/**
* 线程礼让,线程:运行态--->就绪态
* 线程礼让可能不会成功,线程从运行-->就绪 然后直接得到CPU的调度
*/
Thread.yield();
System.out.println(Thread.currentThread().getName()+",end");
}
public static void main(String[] args) {
TestYield testYield = new TestYield();
new Thread(testYield,"T1").start();
new Thread(testYield,"T2").start();
}
}
4.5 线程等待_ join,调用join方法的线程先执行,其他线程等待被阻塞
public class TestJoin implements Runnable{
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println("子线程,i="+i+"=============");
}
}
public static void main(String[] args) {
TestJoin testJoin = new TestJoin();
Thread thread = new Thread(testJoin);
thread.start();
for (int i = 0; i < 200; i++) {
if (i == 100){
try {
//当i为100时,让thread线程执行完,等待thread执行
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("main方法,i="+i);
}
}
}
4.5线程的状态_State,线程只能启动一次
public class TestState {
public static void main(String[] args) {
Thread thread = new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
Thread.sleep(100);
System.out.println(Thread.currentThread().getName()+",i="+i);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
Thread.State state = thread.getState();
System.out.println("=====执行start方法前的状态:"+state);
thread.start();
state = thread.getState();
System.out.println("=====执行start方法后的状态:"+state);
while (state != Thread.State.TERMINATED){
System.out.println("=====执行start方法后的状态:"+state+"======");
try {
Thread.sleep(150);
} catch (InterruptedException e) {
e.printStackTrace();
}
state = thread.getState();
}
state = thread.getState();
System.out.println("=====状态:"+state);
}
}
4.6 线程的优先级_priority
public class TestPriority implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"-->"+Thread.currentThread().getPriority());
}
public static void main(String[] args) {
System.out.println(Thread.currentThread().getName()+"-->"+Thread.currentThread().getPriority());
TestPriority testPriority = new TestPriority();
Thread t1 = new Thread(testPriority,"t1");
Thread t2 = new Thread(testPriority,"t2");
Thread t3 = new Thread(testPriority,"t3");
Thread t4 = new Thread(testPriority,"t4");
Thread t5 = new Thread(testPriority,"t5");
/**
* 1<=Priority<=10
*/
t1.setPriority(Thread.MIN_PRIORITY);
t1.start();
t2.setPriority(3);
t2.start();
t3.setPriority(6);
t3.start();
t4.setPriority(1);
t4.start();
t5.setPriority(Thread.MAX_PRIORITY);
t5.start();
}
}
4.7守护线程_daemon
线程分为用户线程和守护线程,当用户线程执行完,当前没有任何的用户线程执行,守护线程也就结束
public class TestDaemon {
public static void main(String[] args) {
I i = new I();
God god = new God();
Thread daemonThread = new Thread(god);
//将当前线程设置为守护线程
daemonThread.setDaemon(true);
daemonThread.start();
new Thread(i).start();
}
}
class I implements Runnable{
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println("我活了"+i+"年");
}
}
}
class God implements Runnable{
@Override
public void run() {
while (true){
System.out.println("时间很快,又过了一年");
}
}
}
五.线程的同步
5.1 并发
并发:同一个对象被多个线程同时操作
银行取钱,买票等都涉及并发问题
不安全的集合案例:线程安全问题
public class UnSafeCollection{
public static void main(String[] args) {
/**
* 不安全的集合:ArrayList
* 安全的:
*/
List<String> unSafeColl = new ArrayList<>();
List<String> safeColl = new Vector<>();
for (int i = 0; i < 100; i++) {
new Thread(()->{
unSafeColl.add(Thread.currentThread().getName());
safeColl.add(Thread.currentThread().getName());
}).start();
}
System.out.println("unSafeColl size : "+unSafeColl.size());
System.out.println("safeColl size : "+safeColl.size());
}
}
运行结果:
5.2线程同步
5.2.1同步方法_synchronized
线程在并发时(多个线程访问同一个对象),出现了线程的不安全问题,例如买票
public class BuyTicket implements Runnable{
public Integer ticketNubs = 10;
public boolean exitBool = true;
@Override
public void run() {
while (exitBool){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
this.buy();
}
}
/**
* synchronized修饰的方法就是线程同步方法
* 不加synchronized会产生线程的不安全问题
*/
private synchronized void buy(){
if (ticketNubs > 0){
System.out.println(Thread.currentThread().getName()+"买了1张票,还有"+ticketNubs--);
}else if (ticketNubs <= 0){
exitBool = false;
}
}
public static void main(String[] args) {
BuyTicket buyTicket = new BuyTicket();
new Thread(buyTicket,"t1").start();
new Thread(buyTicket,"t2").start();
new Thread(buyTicket,"t3").start();
}
}
运行结果:
5.2.2同步块
进行同步的方法二:同步代码块
public class SynchronizedBlock {
public static void main(String[] args) {
List<String> unSafeList = new ArrayList();
List<String> safeList = new Vector<>();
for (int i = 0; i < 100; i++) {
/**
* 同步块
* ()里面是要锁定的对象
*/
new Thread(()->{
synchronized (unSafeList){
unSafeList.add(Thread.currentThread().getName());
}
safeList.add(Thread.currentThread().getName());
}).start();
}
try {
//等待全部线程执行完
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("unSafeList size : "+unSafeList.size());
System.out.println("safeList size : "+safeList.size());
}
}
六.锁
6.1死锁
案例:用一双筷子吃饭
/**
* 死锁:多个线程互相占有对方想要的资源
*/
public class DeadLock extends Thread{
public static void main(String[] args) {
DeadLock one = new DeadLock(1);
DeadLock two = new DeadLock(2);
one.start();
two.start();
}
public static ChopstickOne chopstickOne = new ChopstickOne();
public static ChopstickTwo chopstickTwo = new ChopstickTwo();
public Integer choose;
public DeadLock(Integer choose){
this.choose = choose;
}
@Override
public void run() {
try {
eat();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
/**
*choose为1:先拿到第一只筷子,休眠1秒等待其他线程执行,然后拿到第二只筷子
*choose为2:先拿到第二只筷子,休眠2秒等待其他线程执行,然后拿到第一只筷子
*/
private void eat() throws InterruptedException {
if (choose == 1){
synchronized (chopstickOne){
System.out.println(Thread.currentThread().getName()+"拿到了,chopstickOne锁");
Thread.sleep(1000);
/**
* 死锁解决:把这个同步块放在外面和上一个同步块处于平级位置
*/
synchronized (chopstickTwo){
System.out.println(Thread.currentThread().getName()+"拿到了,chopstickTwo");
}
}
}else if (choose == 2){
synchronized (chopstickTwo){
System.out.println(Thread.currentThread().getName()+"拿到了,chopstickTwo");
Thread.sleep(2000);
synchronized (chopstickOne){
System.out.println(Thread.currentThread().getName()+"拿到了,chopstickOne锁");
}
}
}
}
}
/**
* 筷子1:第一只筷子
*/
class ChopstickOne{}
/**
* 筷子2:第二只筷子
*/
class ChopstickTwo{}
6.2可重入锁,显式的锁
public class TestLock implements Runnable{
public Integer numbers = 10;
public Boolean flag = true;
ReentrantLock lock = new ReentrantLock();
@Override
public void run() {
try {
Thread.sleep(100);
//加锁
lock.lock();
while(flag){
if (numbers <= 0){
flag = false;
}
System.out.println(Thread.currentThread().getName()+"买了一张票,票还有:"+numbers--);
}
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
//释放锁
lock.unlock();
}
}
public static void main(String[] args) {
TestLock testLock = new TestLock();
new Thread(testLock,"t1").start();
new Thread(testLock,"t2").start();
new Thread(testLock,"t3").start();
}
}