线程
进程:在操作系统中运行的程序,一个进程可以包含多个线程
程序就是指令和数据的有序集合,静态概念
进程就是执行程序的一次执行过程,动态概念系统资源分配的单元
一个进程中包含多个线程,一个进程至少包含一个线程
线程时cpu调度和执行的单位
线程是独立的执行路径
程序运行时,即使没有自己创建线程。后台也会有多个线程,如主线程,gcxianc
main()是主线程,为系统的入口,用于执行整个程序
在一个进程中如果开辟了多个线程,线程的运行由调度器进行安排调度,调度器与操作系统密切相关,先后顺序不能干预
对同一份资源操作时,会存在资源抢夺的问题,加入并发控制
线程会带来额外的开销
每个线程对自己的工作内存交互,内存控制不当会造成数据不一致
线程创建Thread、Runnable、Callable
继承Thread
1.自定义线程类继承Thread类
重新run()方法,编写线程执行体
创建线程对象,调用start方法();
使用Thread实现网图下载:
package com.ty.threadAndRunableAndCallable;
import org.apache.commons.io.FileUtils;
import java.io.File;
import java.io.IOException;
import java.net.URL;
public class ThreadDownLoader extends Thread {
private String url;//网图地址
private String fileName;//
public ThreadDownLoader(String url,String fileName){
this.url = url;
this.fileName = fileName;
}
@Override
public void run(){
WebDownLoader webDownLoader = new WebDownLoader();
webDownLoader.downLoader(url,fileName);
System.out.println("文件名:"+ fileName);
}
public static void main(String[] args) {
ThreadDownLoader t1 = new ThreadDownLoader("https://pic.rmb.bdstatic.com/bjh/914b8c0f9814b14c5fedeec7ec6615df5813.jpeg", "1.jpeg");
ThreadDownLoader t2 = new ThreadDownLoader("https://n.sinaimg.cn/sinakd2020723s/213/w2048h1365/20200723/3918-iwtqvyk4060964.jpg", "2.jpg");
ThreadDownLoader t3 = new ThreadDownLoader("https://file.ccmapp.cn/group1/M00/16/64/rApntl7CSdeAbpYqABArOjGaasg001.jpg", "3.jpg");
t1.start();
t2.start();
t3.start();
}
}
class WebDownLoader{
public void downLoader(String url,String fileName){
try {
FileUtils.copyURLToFile(new URL(url),new File(fileName));
} catch (IOException e) {
e.printStackTrace();
System.out.println("IO exception!!! downLoader Error!!!");
}
}
}
实现Runnable
定义MyRunnable类实现Runnable接口
实现run()方法,编写线程体
创建线程对象,调用start()方法启动线程
Thread和Runnable区别
Thread不建议使用,避免OOP单继承局限,
Runnable具有多线程能力
启动线程:传入目标对象+Thread对象.start()
推荐是哦哟牛皋,避免单继承的局限性,灵活方便,方便同一个对象被多个线程使用
多线程模拟出票:并发问题
package com.ty.threadAndRunableAndCallable;
public class ConcurrencyQuestion implements Runnable {
private int tickerNums = 10;
@Override
public void run() {
while (true){
if (tickerNums <= 0){
break;
}
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"拿到了,第"+(tickerNums--)+"票");
}
}
public static void main(String[] args) {
ConcurrencyQuestion concurrencyQuestionTicker = new ConcurrencyQuestion();
new Thread(concurrencyQuestionTicker,"aa").start();
new Thread(concurrencyQuestionTicker,"bb").start();
new Thread(concurrencyQuestionTicker,"cc").start();
}
}
多线程模拟龟兔赛跑
package com.ty.threadAndRunableAndCallable;
public class ConcurrencyRace implements Runnable{
private String winner;
@Override
public void run() {
for (int i = 1; i <= 100; i++) {
//模拟兔子休息
if (Thread.currentThread().getName().equals("兔子") && i % 2 == 0){
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
boolean flag = gameOver(i);
while (flag){
break;
}
System.out.println(Thread.currentThread().getName()+"--->跑了"+i+"步");
}
}
//判断游戏胜利
private boolean gameOver(int gepts){
if (winner != null){
return true;
}
if (gepts == 100){
System.out.println("=============");
winner = Thread.currentThread().getName();
System.out.println("winner is "+ winner);
return true;
}
System.out.println("=====w========");
return false;
}
public static void main(String[] args) {
ConcurrencyRace race = new ConcurrencyRace();
new Thread(race,"兔子").start();
new Thread(race,"乌龟").start();
}
}
实现Callable
package com.ty.threadAndRunableAndCallable;
import org.apache.commons.io.FileUtils;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class CallableWebDownLoader implements Callable<Boolean> {
private String url; //网图地址
private String name;//保存地址
public CallableWebDownLoader(String url,String name){
this.url = url;
this.name = name;
}
@Override
public Boolean call() throws Exception {
WebDownLoaderUseCallable callable = new WebDownLoaderUseCallable();
callable.downLoader(url,name);
System.out.println("文件名: "+ name);
return true;
}
public static void main(String[] args) {
CallableWebDownLoader c1 = new CallableWebDownLoader(
"https://pic.rmb.bdstatic.com/bjh/914b8c0f9814b14c5fedeec7ec6615df5813.jpeg",
"D:\\software\\JavaCode\\javaSE\\JavaSE01\\src\\com\\ty\\threadAndRunableAndCallable\\1.jpeg");
CallableWebDownLoader c2 = new CallableWebDownLoader("" +
"https://n.sinaimg.cn/sinakd2020723s/213/w2048h1365/20200723/3918-iwtqvyk4060964.jpg",
"D:\\software\\JavaCode\\javaSE\\JavaSE01\\src\\com\\ty\\threadAndRunableAndCallable\\2.jpg");
CallableWebDownLoader c3 = new CallableWebDownLoader(
"https://file.ccmapp.cn/group1/M00/16/64/rApntl7CSdeAbpYqABArOjGaasg001.jpg",
"D:\\software\\JavaCode\\javaSE\\JavaSE01\\src\\com\\ty\\threadAndRunableAndCallable\\3.jpg");
ExecutorService es = Executors.newFixedThreadPool(1);
es.submit(c1);
es.submit(c2);
es.submit(c3);
es.shutdown();
}
}
class WebDownLoaderUseCallable{
public void downLoader(String url,String name) {
try {
FileUtils.copyURLToFile(new URL(url),new File(name));
} catch (IOException e) {
e.printStackTrace();
System.out.println("IO Exception, DownLoad Error!!!");
}
}
}
静态代理
真是对象和代理对象都要实现一个接口
代理对象要代理真是对象
好处:代理对象可以做真实对象做不了的事情,真实对象可以专注做自己的事情
package com.ty.threadAndRunableAndCallable;
public class staticProxy {
public static void main(String[] args) {
HappyCompany happyCompany = new HappyCompany(new You());
happyCompany.HappyMarry();
}
}
interface Marry{
void HappyMarry();
}
//真实角色
class You implements Marry {
@Override
public void HappyMarry() {
System.out.println("结婚了!我们结婚了!!!");
}
}
//代理角色
class HappyCompany implements Marry{
private Marry target;
public HappyCompany(Marry target){
this.target = target;
}
@Override
public void HappyMarry() {
after();
this.target.HappyMarry();
before();
}
private void after() {
System.out.println("布置现场。。。。");
}
private void before() {
System.out.println("收拾现场。。。。。");
}
}
线程状态
五大状态:创建状态、就绪状态、阻塞状态、死亡状态、运行状态
线程执行流程
线程方法
停止线程
并不推荐使用stop(),destroy()
推荐线程自己停下来
建议使用一个标志位进行终止变量,flag=false 则终止线程
线程休眠Sleep
package com.ty.threadAndRunableAndCallable;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
public class CountDown{
private static void countDown(){
int count = 10;
while (true){
try {
Thread.sleep(1000);
count--;
if (count<0){
break;
}
System.out.println(count);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
//countDown();
ControlTime();
}
//打印系统时间
private static void ControlTime(){
Date date = new Date(System.currentTimeMillis());//打印系统时间
while (true){
try {
Thread.sleep(1000);
System.out.println(new SimpleDateFormat("HH:dd:ss").format(date));
date = new Date(System.currentTimeMillis());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
线程礼让 yield
package com.ty.threadAndRunableAndCallable;
public class ThreadYield {
public static void main(String[] args) {
Yield yield = new Yield();
new Thread(yield,"a").start();
new Thread(yield,"b").start();
}
}
class Yield implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"线程执行");
Thread.yield();
System.out.println(Thread.currentThread().getName()+"线程结束");
}
}
合并线程Join
待此线程执行结束后,在执行其他线程,其他线程阻塞
可以想象成插队
package com.ty.threadAndRunableAndCallable;
public class ThreadJoin implements Runnable{
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println("vip 来了"+i);
}
}
public static void main(String[] args) {
ThreadJoin join = new ThreadJoin();
Thread thread = new Thread(join);
thread.start();
for (int i = 0; i < 20; i++) {
if (i==10){
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("main----"+i);
}
}
}
线程状态观测
一个线程可以在给定时间点处于一个状态,这些状态时不反应任何操作系统线程状态的虚拟机状态
package com.ty.threadAndRunableAndCallable;
public class ThreadState {
public static void main(String[] args) {
Thread thread = new Thread(()->{
for (int i = 0; i < 5; i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("=============");
});
//观察线程状态
Thread.State state = thread.getState();
System.out.println(state); // new
thread.start();
state = thread.getState();
System.out.println(state);//run
while (state != Thread.State.TERMINATED){//Thread.State.TERMINATED 线程不终止
try {
Thread.sleep(100);
state = thread.getState();
System.out.println(state);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
线程优先级
package com.ty.threadAndRunableAndCallable;
public class ThreadPriority {
public static void main(String[] args) {
getThreadPriority getThreadPriority = new getThreadPriority();
Thread t1 = new Thread(getThreadPriority);
Thread t2 = new Thread(getThreadPriority);
Thread t3 = new Thread(getThreadPriority);
Thread t4 = new Thread(getThreadPriority);
Thread t5 = new Thread(getThreadPriority);
Thread t6 = new Thread(getThreadPriority);
t1.setPriority(1);
t1.start();
t2.setPriority(3);
t2.start();
t3.setPriority(5);
t3.start();
t4.setPriority(7);
t4.start();
t5.setPriority(Thread.MAX_PRIORITY);
t5.start();
t6.start();
}
}
class getThreadPriority implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"-----"+Thread.currentThread().getPriority());
}
}
守护线程demon
线程同步
并发:多个线程同时操作同一资源
由于同一进程的多个线程共享同一块内存空间,方便的同时也带来了访问冲突问题,为了保证数据在方法中被访问时的正确性,访问时,加入锁机制synchronized,当一个线程获得对象的排他锁,独占资源时,其他线程必选等待,使用后释放锁即可。
同步方法
同步块
同步块:synchronized() {}
同步块解决买票、银行取钱、集合不安全问题
//买票
package com.ty.threadAndRunableAndCallable.notSoft;
public class ThreadNotSoftQuestion {
public static void main(String[] args) {
buyTicket buyTicket = new buyTicket();
new Thread(buyTicket,"aa").start();
new Thread(buyTicket,"bb").start();
new Thread(buyTicket,"cc").start();
}
}
class buyTicket implements Runnable{
private int num= 10;
private boolean flag = true;
@Override
public void run() {
while (flag){
buy();
}
}
private synchronized void buy(){
if (num <= 0){
flag = false;
return;
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"---抢到了第 "+(num--)+"张票");
}
}
package com.ty.threadAndRunableAndCallable.notSoft;
//银行取钱:两个人取钱
public class NotSoftBank {
public static void main(String[] args) {
Account account = new Account(100, "基金");
Drawing you = new Drawing(account,50,"tt");
Drawing girlFriend = new Drawing(account, 100, "yy");
you.start();
girlFriend.start();
}
}
//银行
class Account{
int money;// 余额
String name;//卡号
public Account(int money,String name){
this.money = money;
this.name = name;
}
}
//模拟取钱
class Drawing extends Thread{
private Account account;//账户
private int drawingMoney;//取了多少
private int nowMoney;//现在剩余
public Drawing(Account account,int drawingMoney,String name){
super(name);
this.account = account;
this.drawingMoney = drawingMoney;
}
@Override
public void run(){
synchronized (account){
if (account.money - drawingMoney < 0){
System.out.println(Thread.currentThread().getName()+"余额不足,无法取出");
return;
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//余额
account.money = account.money - drawingMoney;
//手里
nowMoney = nowMoney + drawingMoney;
System.out.println(account.name+"余额为:"+account.money);
System.out.println(this.getName()+"手里的钱:"+nowMoney);
}
}
}
package com.ty.threadAndRunableAndCallable.notSoft;
import java.util.ArrayList;
import java.util.List;
public class NotSoftList {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
for (int i = 0; i < 100; i++) {
new Thread(()->{
synchronized (list){
list.add(Thread.currentThread().getName());
}
}).start();
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(list.size());
}
}
死锁
避免死锁的四个方法
锁 Lock
synchronized和lock的区别
线程协作
##线程通信
均是Object类的方法,都只能在同步方法或者同步代码块中使用,否则就会抛出异常。
线程池
corePoolSize:核心池的大小
maximumPoolSize:最大线程数
keepAliveTime:线程没有任务时最多保持多长时间会终止
package com.ty.threadAndRunableAndCallable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
//线程池
public class pool {
public static void main(String[] args) {
poolTest poolTest = new poolTest();
ExecutorService es = Executors.newFixedThreadPool(10);
es.submit(poolTest);
es.submit(poolTest);
es.submit(poolTest);
es.submit(poolTest);
es.shutdown();
}
}
class poolTest implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
}