线程
线程和进程
1.什么是进程
对于操作系统来说,一个进程就是一个应用程序,多进程就是多个程序同时运行罢了.
2.什么是线程
线程就是相对于进程而说的,一个进程包括很多线程.例如一个360杀毒软件,里面有杀毒,有清理内存垃圾等多个线程.因此线程是资源分配的最小单位,也是CPU调度的最小单位.
线程主要分为五大方面:
(1)线程的创建方式
这里主要讲两种创建方法
1.继承Thread方法;重写Thread中run方法.
public class ThreadTest extends Thread{
public static void main(String[] args) {
new ThreadTest().start();***//开启线程***
for (int i = 0; i <10; i++) {
System.out.println("嘿嘿"+i);
}
}
public void run(){**//重写run方法**
for (int i = 0; i <10; i++) {
System.out.println("哈哈"+i);
}
}
}
2.实现runnable接口;重写run方法.(***常用***)
public class CreateThread implements Runnable{
public static void main(String[] args) {
CreateThread ct = new CreateThread();
Thread th = new Thread(ct);
th.start();***//开启线程***
for(int i=1;i<=100;i++){
System.out.println(i+"一边唱歌");
}
}
@Override
public void run() {
for(int i=1;i<=100;i++){
System.out.println(i+"一边吃饭");
}
}
}
(2)线程状态问题
线程主要分为五大状态
1.新生状态
主要通过new Thread时候就已经创建
2.就绪状态
(1)调用start时候可以进入该状态,等待CPU调度.(2)阻塞状态解除.(3)线程切换.(4)调用yield()礼让线程.
public class YieldTest implements Runnable{
public static void main(String[] args) {
new Thread(new YieldTest(),"A").start();
Thread.yield();
new Thread(new YieldTest(),"B").start();;
}
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"开始");
Thread.yield();//礼让线程,释放资源,重新竞争
System.out.println(Thread.currentThread().getName()+"结束");
}
}
3.阻塞状态
进入阻塞状态主要有三种方法
1.sleep()
2.wait()
3.join()
public class JoinThread {
public static void main(String[] args) {
Father f = new Father();
Thread th = new Thread(f);
th.start();
}
}
class Father implements Runnable{
@Override
public void run() {
System.out.println("爸爸想吸烟");
System.out.println("儿子帮我去买烟");
System.out.println("给儿子钱买烟");
Thread th = new Thread(new Son());
th.start();
try {
th.join()***;//加入线程***
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
System.out.println("找儿子");
}
System.out.println("爸爸接过烟抽一口");
}
}
class Son implements Runnable{
@Override
public void run() {
System.out.println("儿子接过钱");
System.out.println("儿子去买烟");
System.out.println("儿子遇到一游戏厅");
for(int i=1;i<=10;i++){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("儿子玩了"+i+"秒");
}
System.out.println("儿子玩完游戏去买烟");
System.out.println("儿子买好烟了");
}
}
4.运行状态
已经获取CPU的资源,进行运行.
5.终止状态
该线程结束了,一旦到达此状态,线程没有办法恢复.进入的方法一种是程序执行完毕,一种是手动标识.
注意:获取线程状态的方法为getState().
public class StateThread {
public static void main(String[] args) {
Thread th = new Thread(()->{
for (int i = 0; i < 11; i++) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("一遍哈哈..."+i);
}
});
System.out.println(th.getState());//new状态
th.start();
for(int i =1;i<=10;i++){
if(i==5){
try {
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.println(th.getState());
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(th.getState());//终止状态
}
}
(3)线程安全问题
使用场景:
多个线程,同时执行,同时操作同一个资源的时候,才可能会出现线程不安全问题.
解决办法:
通过synchronized 关键字控制线程安全,从而控制多线程排队执行.
这里主要通过同步方法和同步块来完成.
1.同步方法:可以是静态方法和成员方法
2.同步块 synchrojnized(引用类型变量){//l类.class//this//成员变量的引用
}
public class Web123 implements Runnable{
Ticket ticket = new Ticket();
public static void main(String[] args) {
Web12306 web = new Web12306();
Thread th0 = new Thread(web,"0");
Thread th1 = new Thread(web,"1");
Thread th2 = new Thread(web,"2");
th0.start();
th1.start();
th2.start();
}
@Override
public void run() {
while(true){
synchronized(***ticket***){***//锁的是地址//Web123.class//this(当前对象)***
if(ticket.num<=0){
break;
}else{
try {
Thread.sleep(10);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"正在购买第"+ticket.num--+"张票");
}
}
}
}
}
class Ticket{
int num=100;
}