您的位置:首页 > 编程语言 > Java开发

java进程、线程、线程生命周期,创建线程的五种方法、以及多线程并发同步问题。

2019-08-20 14:10 417 查看
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 本文链接:https://blog.csdn.net/leilei7407/article/details/99841944

1.程序、进程、线程、并行、并发

程序:一段静态的代码。

进程:程序的一次动态执行过程。进程基于操作系统,运行在内存中。如windows就是一个多任务系统,可以同时运行多个应用程序。

线程:在一个程序中同时运行的多个独立的流程,每一个独立的流程就是线程。

进程和线程有时也被称为任务。

线程并发:多个线程并发执行。

并行:并行是指两个或者多个事件在同一时刻发生,同时运行。只有具备多个cpu才能实现并行。

并发:并发是指两个或多个事件在同一时间间隔发生。是伪并行,即看起来是同时运行。单个cpu+多道技术就可以实现并发。

而无论是并行还是并发,在用户看来都是“同时”运行的。

主线程:当JVM启动后,加载类文件,发现main方法,那么就会为main方法创建一个线程,这个为main方法创建的线程称为主线程。

一个进程中可以有多个任务一起执行,每一个任务都被称为一个线程。线程依赖于进程,在进程中运行·,不能独立存在。每个进程中至少有一个线程,被称为主线程。只有当程序中所有的线程都结束之后,程序才会结束。

线程随机性:正常情况下,线程是随机的,谁先执行是不确定的,如果我们想控制顺序,需要自己编写代码。

2.创建线程的五种写法以及java中多线程代码的编写

方法1:直接Thread t=new Thread(); t.start(); 这种方法程序可以运行,但没有什么意义,因为原始线程run()方法里什么也没有。start开始即结束。
方法2:继承Thread,重写run方法;
方法3:实现Runnable ,new Thread();
方法4:Thread匿名内部类
方法5:Runnable匿名内部类

下面给出用五种方法来创建线程的代码示例:
定义EatThread类,继承Thread,重写run()方法

package test;
//继承Thread,重写run()方法
public class EatThread extends Thread {

@Override
public void run() {

for(int i=1;i<3;i++)
{

//每隔0.1秒吃一口
System.out.println(this.getName()+"吃一口!");
try {

//等待0.1秒
sleep(100); //也可以写成this.sleep(100)或者Thread.sleep(100);

} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(this.getName()+"线程结束");
}
}

定义PhoneThread类,实现Runnable接口

package test;
//实现Runnable接口
public class PhoneThread  implements Runnable {

@Override
public void run() {

//获取当前正在执行这段代码的线程
Thread now =Thread.currentThread();
for(int i=1;i<3;i++)
{
//每隔0.1秒玩一次手机
System.out.println(now.getName()+"玩手机");//注意:此处不能写成this.getName()
try {

//等待0.1秒
now.sleep(100); //或者写成Thread.sleep(100)
//注意:此处不能写成sleep(100)或者this.sleep(100),会报错
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(now.getName()+"线程结束");
}
}

主函数,五种创建方法

package test;

public class Test {

public static void main(String[] args) {

/**
* 第一种:直接new thread(),这种方法没有什么意义
*/
Thread t1=new Thread();
t1.setName("1");
t1.start();
/**
* 第二种,继承Thread,重写run()方法
*/
EatThread t2=new EatThread();
t2.setName("2");
t2.start();
/**
* 第三种,实现Runnable接口
*/
PhoneThread pt=new PhoneThread();
Thread t3=new Thread(pt);
Thread t4=new Thread(new PhoneThread());//此处也可以写成Thread t4=new Thread(pt);
t3.setName("3");//也可以在创建线程的时候直接命名Thread t3=new Thread(pt,"3");
t4.setName("4");
t3.start();
t4.start();
/**
* 第四种,Thread匿名内部类,仅适合局部使用
*/
new Thread("5") {
@Override
public void run() {
for(int i=1;i<3;i++)
{
//每隔0.1秒站一下
System.out.println(this.getName()+"站起来!");
try {

//等待0.1秒
sleep(100); //也可以写成this.sleep(100)或者Thread.sleep(100);

} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(this.getName()+"线程结束");
}
}.start();
/**
* 第五种:Runnable匿名内部类
*/
Thread t6=new Thread(new Runnable() {

@Override
public void run() {
Thread now=Thread.currentThread();
for(int i=1;i<3;i++)
{
//每隔0.1秒坐一下
System.out.println(now.getName()+"坐下去!");
try {

//等待0.1秒
Thread.sleep(100); //或者now.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(now.getName()+"线程结束");
}

},"6");

t6.start();
}
}

运行结果:

2吃一口!
3玩手机
4玩手机
5站起来!
6坐下去!
3玩手机
2吃一口!
4玩手机
6坐下去!
5站起来!
3线程结束
2线程结束
5线程结束
6线程结束
4线程结束

3.线程的生命周期

新建、就绪、运行、阻塞、死亡总共5种状态
(1)新建:创建一个线程;

(2)就绪:执行start()之后就处于就绪状态,时刻准备着被cpu执行。

(3)运行:线程得到了cpu资源进行运行,但只有一小段时间片;时间到了之后,cpu就切换到其他线程,当前线程又变为就绪状态。

(4)堵塞:睡眠sleep(毫秒)、等待wait()、等待队列join()、

(5)死亡:run执行结束或者中途被其他线程杀死

自然死亡:正常运行run()方法结束后终止

异常终止:调用stop()等方法杀死

4.多线程同步问题

以存钱取钱为例,说明线程同步问题。

先看如下代码,张三存钱,存10次,每次存100元。李四取钱,取10次,每次取100元。

package test;

//账户
public class Account {

static  private double n; //定义账户余额

public double getN() {
return n;
}

public void setN(double n) {
this.n = n;
}
}
package test;

public class Tongbu {

public static void main(String[] args) {

Account ac =new Account();
ac.setN(1000); //账户当前余额1000元
System.out.println("最开始余额为:"+ac.getN());

new Thread("张三") {
@Override
public void run() {
try {
for(int i=1;i<=10;i++) {
//获取当前账户余额
double n=ac.getN();

//向账户中存出100
n=n+100;
sleep(1);
ac.setN(n);

//输出当前账户余额
System.out.println(this.getName()+"存100后余额为:"+n);
}

}catch (InterruptedException e) {
e.printStackTrace();
}
}
}.start();

new Thread("李四") {
@Override
public void run() {
try {
for(int i=1;i<=10;i++) {
//获取当前账户余额
double n=ac.getN();

//从账户中取出100
n=n-100;
sleep(1);
ac.setN(n);

//输出当前账户余额
System.out.println(this.getName()+"取100后余额为:"+n);
}

}catch (InterruptedException e) {
e.printStackTrace();
}
}
}.start();
}

}

运行结果为:

最开始余额为:1000.0
张三存100余额后为:1100.0
李四取100后余额为:900.0
张三存100余额后为:1200.0
李四取100后余额为:800.0
张三存100余额后为:1300.0
李四取100后余额为:700.0
张三存100余额后为:1400.0
李四取100后余额为:600.0
张三存100余额后为:1500.0
李四取100后余额为:500.0
张三存100余额后为:1600.0
李四取100后余额为:400.0
张三存100余额后为:1700.0
李四取100后余额为:300.0
张三存100余额后为:1800.0
李四取100后余额为:200.0
张三存100余额后为:1900.0
李四取100后余额为:100.0
张三存100余额后为:2000.0
李四取100后余额为:0.0

从上面的结果看出,这并不是我们想要的结果,最终余额应该仍为1000。

解决方案:加锁,synchronized

synchronized里面的代码是一个整体,必须执行完,即使里面有sleep,其他的线程也要等待这一段执行完。

synchronized:线程同步,让线程排队。
锁:使用不同的锁就有不同的队伍

package test;

public class Tongbu {

public static void main(String[] args) {

Account ac =new Account();
ac.setN(1000); //账户当前余额1000元
System.out.println("最开始余额为:"+ac.getN());

new Thread("张三") {
@Override
public void run() {
try {

for(int i=1;i<=10;i++) {
//加锁,ac为大家都认识的对象,不能加一个只有你自己认识的锁
synchronized(ac) {
//获取当前账户余额
double n=ac.getN();

//向账户中存出100
n=n+100;
sleep(1);
ac.setN(n);

//输出当前账户余额
System.out.println(this.getName()+"存100后余额为:"+n);
}
}

}catch (InterruptedException e) {
e.printStackTrace();
}
}
}.start();

new Thread("李四") {
@Override
public void run() {
try {
for(int i=1;i<=10;i++) {
//加锁,ac为大家都认识的对象
synchronized(ac) {
//获取当前账户余额
double n=ac.getN();

//从账户中取出100
n=n-100;
sleep(1);
ac.setN(n);

//输出当前账户余额
System.out.println(this.getName()+"取100后余额为:"+n);
}

}

}catch (InterruptedException e) {
e.printStackTrace();
}
}
}.start();
}
}

运行结果:

最开始余额为:1000.0
张三存100后余额为:1100.0
张三存100后余额为:1200.0
张三存100后余额为:1300.0
张三存100后余额为:1400.0
张三存100后余额为:1500.0
李四取100后余额为:1400.0
李四取100后余额为:1300.0
李四取100后余额为:1200.0
李四取100后余额为:1100.0
李四取100后余额为:1000.0
李四取100后余额为:900.0
李四取100后余额为:800.0
李四取100后余额为:700.0
李四取100后余额为:600.0
李四取100后余额为:500.0
张三存100后余额为:600.0
张三存100后余额为:700.0
张三存100后余额为:800.0
张三存100后余额为:900.0
张三存100后余额为:1000.0

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐