线程:
- 线程就是独立的执行路径;
- 在程序运行时,即使自己没有创建线程,后台也会有多个线程,如主线程、GC线程;
- main()称之为主线程,为系统的入口,用于执行整个程序;
- 在一个进程中,如果开辟了多个线程,线程的运行由调度器安排调度,不一定立刻执行,调度器是与操作系统紧密相关的,前后顺序是不能人为干预的;
- 对同一份资源操作时,会存在资源抢夺问题,需要加入并发控制;
- 线程会带来额外的开销,如cpu调度时间,并发控制开销;
- 每个线程在自己的工作内存交互,内存控制不当会造成数据不一致;
三种创建方式:
- 继承Thread类
import org.apache.commons.io.FileUtils;
import java.io.File;
import java.io.IOException;
import java.net.URL;
public class Thread1 extends Thread {
private String url;
private String name;
public Thread1(String url, String name) {
this.url = url;
this.name = name;
}
@Override
public void run() {
WebDownloader webDownloader = new WebDownloader();
webDownloader.downLoader(url, name);
System.out.println("下载了文件名为" + name);
}
public static void main(String[] args) {
Thread1 thread1 = new Thread1("https://ss0.bdstatic.com/70cFuHSh_Q1YnxGkpoWK1HF6hhy/it/u=1729079282,3234823446&fm=26&gp=0.jpg", "a1.jpg");
Thread1 thread2 = new Thread1("https://ss0.bdstatic.com/70cFvHSh_Q1YnxGkpoWK1HF6hhy/it/u=206191374,1505544096&fm=26&gp=0.jpg", "a2.jpg");
Thread1 thread3 = new Thread1("https://ss0.bdstatic.com/70cFvHSh_Q1YnxGkpoWK1HF6hhy/it/u=206191374,1505544096&fm=26&gp=0.jpg", "a3.jpg");
thread1.start();
thread2.start();
thread3.start();
}
}
class WebDownloader{
public void downLoader(String url, String name){
try {
FileUtils.copyURLToFile(new URL(url), new File(name));
} catch (IOException e) {
e.printStackTrace();
}
}
}
- 实现Runnable接口
此处与代理模式相结合
龟兔赛跑
package com.company.demo01;
public class Race implements Runnable {
private String winner;
@Override
public void run() {
for (int i = 0; i <= 100; i++) {
if (Thread.currentThread().getName().equals("兔子") && i%10 == 0){
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if (gameOver(i)){
break;
}
System.out.println(Thread.currentThread().getName() + "runs" + i + "步");
}
}
private boolean gameOver(int i) {
if (winner != null){
return true;
}
if (i >= 100){
winner = Thread.currentThread().getName();
System.out.println("Winner : " + winner);
return true;
}
return false;
}
public static void main(String[] args) {
Race race = new Race();
new Thread(race, "rabbit").start();
new Thread(race, "turtle").start();
}
}
- 实现Callable接口
线程状态:
new
就绪
阻塞
运行
dead
线程方法:
setPriority(int newPriority)
static void sleep()
join
yield
停止线程:
不推荐使用stop(), destroy()方法停止
推荐使用一个标志位进行终止变量,当flag = false,则线程停止运行
class TestStop implements Runnable{
private volatile boolean flag = true;
@Override
public void run() {
while (flag){
System.out.println("run。。。" );
}
}
public void stop(){
this.flag = false;
}
}
线程休眠
- sleep(毫秒值)指定当前线程阻塞的毫秒数
- sleep存在异常InterruptedException;
- sleep时间达到后线程进入就绪状态;
- sleep可以模拟网络延迟,倒计时等;
- 每一个对象都有一个锁,sleep不会释放锁。
模拟网络延迟功能
public class TestSleep implements Runnable{
private int ticketNums = 10;
@Override
public void run() {
while (true){
if (ticketNums <= 0){
break;
}
try {
//这里如果不让他 sleep 的话,cpu速度过快,会导致一个线程直接跑完所有,其他线程来不及处理就结束了。
Thread.sleep(200);
}catch (InterruptedException e){
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "拿到了第" + ticketNums-- + "张票");
}
}
public static void main(String[] args) {
TestSleep testSleep = new TestSleep();
new Thread(testSleep, "A").start();
new Thread(testSleep, "B").start();
new Thread(testSleep, "C").start();
}
}
倒计时
public class TestSleep2 {
public static void main(String[] args) throws InterruptedException {
// tenDown();
Date startT = new Date(System.currentTimeMillis());
while (true){
Thread.sleep(1000);
System.out.println(new SimpleDateFormat("HH:mm:ss").format(startT));
startT = new Date(System.currentTimeMillis());
}
}
public static void tenDown() throws InterruptedException {
int num = 10;
while (true){
Thread.sleep(1000);
System.out.println(num --);
if (num <= 0){
break;
}
}
}
}
线程礼让(yield())
- 礼让线程,让当前正在执行的线程暂停,但不阻塞;
- 将线程从运行状态变为就绪状态;
- 让CPU重新调度,礼让不一定成功,看CPU心情;就是让所有线程回到同一起点。
public class TestYield {
public static void main(String[] args) {
MyYield myYield = new MyYield();
new Thread(myYield, "A").start();
new Thread(myYield, "B").start();
}
}
class MyYield implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + "start");
Thread.yield();
System.out.println(Thread.currentThread().getName() + "stop");
}
}
线程强制执行:join()
一旦thread.join(),就必须等这个thread执行完,才能继续往下执行,其他线程阻塞。
public class TestJoin 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 {
TestJoin testJoin = new TestJoin();
Thread thread = new Thread(testJoin);
thread.start();
for (int i = 0; i < 500; i++) {
if (i == 200){
thread.join(); //
}
System.out.println("main" + i);
}
}
}