文章目录
一、线程的概念
程序是对数据描述与操作的一段静态代码的有序集合,是应用程序执行的脚本。进程是程序的一次执行过程,它对应从代码加载、执行到执行完毕的一个完整过程。系统运行一个程序就是个进程从创建、运行到消亡的过程。进程是程序在一个数据集合上运行的过程,是系统进行资源分配和调度的一个独立单位。
线程是比进程更小的运行单位,是能独立运行的基本单位,也是能独立调度和分派的基本单位。一个进程在执行的过程中,可以产生多 个线程,并且这些线程之间可以并发执行,甚至允许在一个进程中所有 的线程都能并发执行。 就好比生活中,我们在听音乐的同时还可以看书一样。
在Java中,线程由三部分组成:虚拟的CPU、代码和数据。
(1)虚拟的CPU:专门用于执行线程的任务。在Java中,由java. lang. Thread类封装和虚拟。
(2)代码:线程中执行的指令,即程序中特定的方法。在Java中,构造Thread类时,传递给Thread类对象。
(3)数据:线程中要处理的数据,即程序中的变量等。
并发: 指两个或多个事件在同一个时间段内发生。
并行: 指两个或多个事件在同一时刻发生(同是发生)。
二、Thread类和Runnable接口
Java中,创建线程的方法有两种:一是通过继承线程类Thread来创建线程;二是建立一个实现Runnable接口的类。
演示如下:
package com.hg.day22.demo01;
public class Person extends Demo01MAainThread{
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Person(){
}
public Person(String name){
this.name = name;
}
public void run(){
for (int i = 0; i <20;i++)
{
System.out.println(name+"--->"+i);
}
}
}
package com.hg.day22.demo01;
/*
主线程 执行main()方法的线程
单线程程序:只有一个程序
*/
public class Demo01MAainThread {
public static void main(String[] args) {
Person p1=new Person("小强");
p1.run();
// System.out.println(0/0);
Person p2=new Person("小刚");
p2.run();
}
}
运行结果如下:
package com.hg.day22.demo01;
//1、创建子类
public class MyThread extends Thread {
//2、才重写run方法
//重写
@Override
public void run() {
for (int i = 0; i <20;i++)
{
System.out.println("子线程"+i);
}
}
}
package com.hg.day22.demo01;
import com.hg.day22.demo02.MyThread;
/*
java.long.Thread
实现步骤:
创建一个thread类的子类
在thread子类中重写run方法,设置线程任务(干什么)
创建thread子类的对象
调用thread类中的方法start来的启动线程,执行main方法
*/
public class Demo01Thread {
public static void main(String[] args) {
//3、创建子类的对象
com.hg.day22.demo02.MyThread mt=new com.hg.day22.demo02.MyThread();
//4、调用这个方法
mt.start();//子线程0
for (int i = 0; i <20;i++)
{
System.out.println("主线程"+i);
// if(i==10)
// System.out.println(0/0);
}
}
}
运行结果如下:
三、主线程与线程的生命周期
线程是一个动态的执行过程:就如人的生老病死,一个线程的生命周期要经历创建、就绪、运行、挂起、终止5中状态。
创建–>就绪–>运行–>挂起–>终止
演示如下2:
package com.hg.day22.demo02;
//1、创建子类
public class MyThread extends Thread {
//2、才重写run方法
//重写
@Override
public void run() {
// String name =getName();
// System.out.println("run"+name);
System.out.println("子"+Thread.currentThread().getName());
}
}
package com.hg.day22.demo02;
/*
java.long.Thread
实现步骤:
创建一个thread类的子类
在thread子类中重写run方法,设置线程任务(干什么)
创建thread子类的对象
调用thread类中的方法start来的启动线程,执行main方法
*/
public class Demo01Thread {
public static void main(String[] args) {
//3、创建子类的对象
MyThread mt=new MyThread();
//4、调用这个方法
mt.start();//子线程0
new MyThread().start();//子线程1
new MyThread().start();//子线程2
new MyThread().start();//子线程3
System.out.println("main"+Thread.currentThread().getName());
}
}
运行结果如下:
package com.hg.day22.demo02;
public class MyThreadName extends Thread{
public MyThreadName() {}
public MyThreadName(String name) {
super(name);//把线程的名称传递给父类,让父类thread给子线程起一个名字
}
@Override
public void run() {
// String name =getName();
// System.out.println("run"+name);
System.out.println("子:"+Thread.currentThread().getName());
}
}
package com.hg.day22.demo02;
public class Demo02ThreadSetName {
public static void main(String[] args) {
MyThreadName mt=new MyThreadName("小强");
mt.start();
new MyThreadName("旺财").start();
}
}
运行结果如下:
四、线程状态控制方法—线程休眠
如果希望线程休眠一段时间可以使用sleep(long)的方法。
演示如下:
package com.hg.day22.demo03;
public class Demo03Sleep {
public static void main(String[] args) {
for (int i = 1; i <60;i++)
{
System.out.println(i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
运行结果如下:
五、实现runnable接口创建多线程的好处
1、避免了单继承的局限性
2、增强了程序的扩展性,降低了程序的耦合性
演示如下:
package com.hg.day22.demo04;
public class RunableImpl2 implements Runnable {
// @Override
public void run() {
for(int i=0;i<20;i++)
{
System.out.println("hello");
}
}
}
package com.hg.day22.demo04;
//1、创建一个runnable接口实现类
public class RunnableImpl implements Runnable {
//2、在实现类中 重写Override
@Override
public void run() {
for(int i = 0; i <20;i++)
{
System.out.println(Thread.currentThread().getName() +"---->"+i);
}
}
}
package com.hg.day22.demo04;
public class Demo04Runnable {
//3、创建一个runnable接口是实现类 对象
public static void main(String[] args) {
RunnableImpl run =new RunnableImpl();
//4、创建Thread类对象,构造方法中传递Runnable接口实现类对象
// Thread t=new Thread(run);
//5、调用Thread 累计中的start方法,启动子线程
Thread t=new Thread(new RunableImpl2());
t.start();
for(int i = 0; i <20;i++)
{
System.out.println(Thread.currentThread().getName() +"---->"+i);
}
}
}
运行结果如下:
六、实例:使用 synchronized出售电影票
package com.hg.day22.demo05;
/*
解决线程安全的一种方案:使用同步代码块
格式:
synchronized(锁对象){
可能会出现线程安全的代码(是因为访问了共享的数据)
}
注意:
1、通过代码块中的锁对象,可以使用任意的对象
2、但是必须保证多个线程使用的锁对象是同一个
3、锁对象作用:
把同步代码块锁住,只让一个线程执行
*/
public class RunnableImpl implements Runnable{
private int ticket = 100;
Object obj=new Object();
@Override
public void run() {
while (true) {
synchronized (obj) {
if (ticket > 0) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "--->正在卖第" + ticket + "张票");
ticket--;
}
}
}
}
}
package com.hg.day22.demo05;
public class Demo01Ticket {
public static void main(String[] args) {
RunnableImpl run=new RunnableImpl();
Thread t0=new Thread(run);
Thread t1=new Thread(run);
Thread t2=new Thread(run);
t0.start();
t1.start();
t2.start();
}
}
运行结果: