多线程
进程 一个进程下面可以有多个线程
线程 就算没有创建线程 也会有默认的线程 例如 main线程 gc线程
线程五种状态
新生状态:Thread t = new Thread 线程对象一旦创建就进入到新生状态
就绪状态:调用start()方法的时候 线程立即进入就绪状态 但不意味着立即调度执行
运行状态:进入运行状态 线程才真正的执行代码块
阻塞状态:当调用sleep,wait或同步锁定时,线程进入阻塞状态 也就是代码不往下执行。阻 塞状态解除后 重新进入就绪状态 等待cpu调度
死亡状态:线程中断或者结束 一旦进入死亡状态 就不能在启动线程
Thread 代码片
。
//继承Thread类
public class Thread extends java.lang.Thread {
@Override
public void run() {
for (int i = 0; i < 200; i++) {
System.out.println("我在学习"+i);
}
}
public static void main(String[] args) {
Thread thread = new Thread();
// thread.run(); //调用run方法是先执行run方法
thread.start(); //调用start方法是和主线程同时执行
for (int i = 0; i < 2000; i++) {
System.out.println("我在学习多线程"+i);
}
}
}
Thread下载图片小案例 代码片
。
public class ThreadSl extends java.lang.Thread {
private String url = "";
private String name = "";
private ThreadSl (String url,String name){
this.name = name;
this.url = url;
}
@Override
public void run() {
DownloadJpg downloadJpg = new DownloadJpg();
downloadJpg.downLoad(url,name);
System.out.println("下载文件名为"+name);
}
public static void main(String[] args) {
ThreadSl threadSl1 = new ThreadSl("图片地址","图片名称");
ThreadSl threadSl2 = new ThreadSl("图片地址","图片名称");
ThreadSl threadSl3 = new ThreadSl("图片地址","图片名称");
threadSl1.start();
threadSl2.start();
threadSl3.start();
}
class DownloadJpg{
public void downLoad (String url,String name){
try {
FileUtils.copyURLToFile(new URL(url),new File(name));
} catch (IOException e) {
e.printStackTrace();
System.out.println("io异常downLoad方法");
}
}
}
龟兔赛跑 代码片
private static String winner ;
@Override
public void run() {
for (int i = 0; i <= 100; i++) {
if (gamerOver(i)){
return;
}
if (Thread.currentThread().getName().equals("兔子")&& i%10==0){
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName()+"--》跑了"+i+"步");
}
}
public static void main(String[] args) {
GtRunnable gtRunnable = new GtRunnable();
new Thread(gtRunnable,"乌龟").start();
new Thread(gtRunnable,"兔子").start();
}
private boolean gamerOver(int step){
if (winner!=null){ //已经存在胜利者
return true;
}{
if (step >= 100){
winner = Thread.currentThread().getName();
System.out.println("winner =" +winner);
}
}
return false;
}
线程停止 stop
通过自己定义一个标识符 在写一个方法切换标识符 让线程停止
public class Stop implements Runnable{
private boolean flag = true;
@Override
public void run() {
int i =0;
while (flag){
System.out.println("run . . . Thread"+i++);
}
}
public void stop(){
this.flag = false;
}
public static void main(String[] args) {
Stop stop = new Stop();
new Thread(stop).start();
for (int i = 0; i < 1000; i++) {
System.out.println("main主线程"+ i);
if (i==900){
stop.stop(); //方法切换标识符 让线程停止
System.out.println("run线程该结束了");
}
}
}
}
线程sleep
模拟倒计时 代码片
。
public class Sleep implements Runnable{
@Override
public void run() {
int num = 10;
while (true){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(num--);
if (num<0){
break;
}
}
}
public static void main(String[] args) {
Sleep sleep = new Sleep();
new Thread(sleep).start();
}
}
打印当前系统时间 代码片
Date date = new Date(); //获取系统当前时间
while (true){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(new SimpleDateFormat("HH:mm:ss").format(date));
date = new Date();
}
线程礼让 yield 代码片
。
线程礼让:让正在执行的线程暂停 但不阻塞,将线程状态从运行转为就绪,让cpu重新调度 但是不是每次都会礼让成功
public class Yield {
public static void main(String[] args) {
myYield myYield = new myYield();
new Thread(myYield,"a").start();
new Thread(myYield,"b").start();
}
static class myYield implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"开始执行");
Thread.yield(); //线程礼让
System.out.println(Thread.currentThread().getName()+"执行结束");
}
}
}
线程插队join 代码片
。
join合并线程 待此线程执行完毕以后在执行其他线程 其他线程阻塞
public class Join implements Runnable{
@Override
public void run() {
for (int i = 0; i < 200; i++) {
System.out.println("vip来了"+i);
}
}
public static void main(String[] args) throws InterruptedException {
Join join = new Join();
Thread thread = new Thread(join);
thread.start();
for (int i = 0; i < 500; i++) {
System.out.println("main"+i);
if (i==200){
thread.join();
}
}
}
}
Thread.status
NEW 尚未启动的线程处于此状态
RUNNABLE 在JAVA虚拟机中执行的线程处于此状态
BLOCKED 被阻塞的状态
WAITING 正在等待另一个线程执行特定动作的状态
TIME_WAITING 正在等待另一个线程执行动作达到特定时间的状态
TERMINATEN 死亡状态 线程不能再被启动
线程状态 代码片
。
public class Status {
public static void main(String[] args) throws InterruptedException {
java.lang.Thread thread = new java.lang.Thread(()->{
for (int i = 0; i < 5; i++) {
try {
java.lang.Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("/");
});
java.lang.Thread.State state = thread.getState();
System.out.println(state); //new
thread.start(); //启动线程
state = thread.getState();
System.out.println(state); //run
while (state!= java.lang.Thread.State.TERMINATED){
java.lang.Thread.sleep(100);
state = thread.getState();
System.out.println(state); //输出状态
}
}
线程优先级
优先级低只是意味着获得调度的概率低 并不是意味着优先级低就不会被调度 这都是在cpu的态度 意思就是不一定设置了优先级高了就一定会被先执行
实现方法 setPriority() 默认是5 最大是10 最低 1
主线程默认的优先级是5
public class PrioRity {
public static void main(String[] args) {
// 主线程默认的优先级是5
System.out.println(Thread.currentThread().getName()+"优先级是"+Thread.currentThread().getPriority());
MyPriority myPriority = new MyPriority();
Thread t1 = new Thread(myPriority);
Thread t2 = new Thread(myPriority);
Thread t3 = new Thread(myPriority);
Thread t4 = new Thread(myPriority);
Thread t5 = new Thread(myPriority);
Thread t6 = new Thread(myPriority);
t1.start();
t2.setPriority(3);
t2.start();
t3.setPriority(Thread.MAX_PRIORITY);
t3.start();
t4.setPriority(Thread.MIN_PRIORITY);
t4.start();
t5.setPriority(8);
t5.start();
t6.setPriority(6);
t6.start();
}
static class MyPriority implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"优先级是"+Thread.currentThread().getPriority());
}
}
}
守护线程 daemon
用户线程和守护线程 守护线程java虚拟机不会管
默认是false
public class Daemon {
public static void main(String[] args) {
You you = new You();
God god = new God();
Thread thread1 = new Thread(god);
thread1.setDaemon(true);
thread1.start();
new Thread(you).start();
}
static class You implements Runnable{
@Override
public void run() {
for (int i = 0; i < 36500; i++) {
System.out.println("人生不过三万天");
}
System.out.println("===========Good By");
}
}
static class God implements Runnable{
@Override
public void run() {
while (true){
System.out.println("上帝保佑你");
}}
}
}
线程同步
并发 同一个对象被多个线程同时操作
synchronized 实现原理就是队列跟锁
缺陷 会大大影响效率
直接声明synchronized写法 代码片
。
public static void main(String[] args) {
MyTicket myTicket = new MyTicket();
new Thread(myTicket,"我").start();
new Thread(myTicket,"你").start();
new Thread(myTicket,"黄牛").start();
}
static class MyTicket implements Runnable{
private int count = 10;
boolean flag = true;
@Override
public void run() {
while (flag){
try {
buy();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
private synchronized void buy() throws InterruptedException { //直接在方法上加上synchronized
if (count<=0){
flag = false;
return;
}
Thread.sleep(100);
System.out.println(Thread.currentThread().getName()+"拿到"+count--);
}
}
synchronized方法块 代码片
。
public static void main(String[] args) {
Account account = new Account(100, "结婚基金");
DraWing you = new DraWing(account, 50, "你");
DraWing youFriend = new DraWing(account, 100, "youFriend");
you.start();
youFriend.start();
}
static class Account {
int money; //余额
String name; //卡名
public Account(int money, String name) {
this.money = money;
this.name = name;
}
}
static class DraWing extends Thread {
Account account;//账户
int draWingMoney; //取了多少钱
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.money);
System.out.println(this.getName()+"手里余额为"+nowMoney);
}
}
}
public static void main(String[] args) throws InterruptedException {
List<String> list = new ArrayList<String>();
for (int i = 0; i < 10000; i++) {
new Thread(()->{
synchronized (list){
list.add(Thread.currentThread().getName());
}
}).start();
}
Thread.sleep(3000);
System.out.println(list.size());
}
CopyOnWriteArrayList
跟使用synchronized修饰过的arrayList集合是一样的
public class JucList {
public static void main(String[] args) throws InterruptedException {
CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<String> ();
for (int i = 0; i < 10000; i++) {
new Thread(()->{
list.add(Thread.currentThread().getName());
}).start();
}
Thread.sleep(3000);
System.out.println(list.size());
}
}
死锁
死锁就是线程a持有独占锁a并且想获取持有独占锁b的同时线程b也是同样的想获取线程 就会造成死锁
解决办法 尽量使用tryLock设置一个超时时间,超时就退出
产生死锁的四个必要条件
1 互斥条件 一个资源每次只能被一个进程使用
2 请求与保持条件 一个进程因请求资源而堵塞时 对已获得的资源保持不放
3 不剥夺条件 进程使用的资源在没有释放之前不能被强制剥夺
4 循环等待条件 若干进程形成一个头尾相接的循环等待资源的关系
Lock锁
比synchronized性能稍微好一点
public static void main(String[] args) {
lickTo lickTo = new lickTo();
new Thread(lickTo).start();
new Thread(lickTo).start();
new Thread(lickTo).start();
}
static class lickTo implements Runnable{
ReentrantLock lock = new ReentrantLock();
int num = 10;
@Override
public void run() {
try {
lock.lock();
}finally {
while (num>0){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(num--);
}
lock.unlock();
}
}
}
wait
wait和sleep的区别 前者会释放锁
notiyfall 会唤醒同一个对象中所有用到wait方法的线程 根据优先级别来调度
线程池
好处 提高了响应速度
降低资源消耗
便于线程管理
public static void main(String[] args) {
ExecutorService service = Executors.newFixedThreadPool(10);
service.execute(new poolTo());
service.execute(new poolTo());
service.execute(new poolTo());
service.execute(new poolTo());
service.shutdown(); //关闭
}
static class poolTo implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
}
}