[Java][实现多线程的三种方式]

本系列学习笔记简介

传智播客的毕向东Java基础教程是免费公开的一份面向初学者的Java学习教程。在我学习毕老师的Java基础教程过程中,苦于其并没有附带练习题,总觉得学的‘轻飘飘’的,所以决定每天看完的一些内容,总在接下来的几天里找一些时间写下来,看看自己还记得多少,看看自己哪些知识点理解的不透彻。希望本系列学习笔记在帮助自己理清思路,理顺知识点的同时,也能够帮助其他在学习Java的同学。欢迎大家在评论区讨论相关内容。

多线程的继承Thread类实现

进程线程简介

进程可以认为是一个正在运行中的程序,你打开任务管理器就可以看到进程。而线程是这个进程中,为了完成一些任务而相互独立进行的代码集合,比如你在360安全卫士中打开安全检查的同时又可以清扫垃圾,这时你就开启了两个线程。

多线程卖票介绍

我们这里通过一个卖票例子来讲解多线程的继承Thread类实现。我们假设共有100张编号为1到100的票,在命令行打印一个数字就视为卖出了对应编号的票,我们首先采用继承Thread类来实现。
思路:创建一个类来继承Thread类,在子类中重写run()方法来覆盖父类Thread中的run()方法。

代码块

错误代码块
class Ticket extends Thread
{
	private int num = 100;
	public void run()
	{
		while(true)
		{
			if(num>0)
				System.out.println(Thread.currentThread().getName()+"....."+"num="+num--);
		}
	}
}
class TicketDemo 
{
	public static void main(String[] args) 
	{
		Ticket t1 = new Ticket();
		Ticket t2 = new Ticket();
		t1.start();
		t2.start();
	}
}

上述代码的部分运行结果为:
命令行结果
我们看到线程0与线程1卖出了同样的票号,这是我们不希望看到的,这100号座位旅客0坐还是旅客1坐合适啊?究其原因,是因为我们new了两个Ticket对象,每生成一个Ticket对象,JVM虚拟机的堆内存中都会有属于该对象的成员变量num=100,所以num- -的时候每个票号都会出现两次。我们可以选择把num变为静态变量,这样它就会被JVM存储在方法区中,被Ticket对象所共享。

正确代码块
class Ticket extends Thread
{
	private static int num = 100;//我们只是在这里加上了static关键字
	public void run()
	{
		while(true)
		{
			if(num>0)
				System.out.println(Thread.currentThread().getName()+"....."+"num="+num--);
		}
	}
}
class TicketDemo 
{
	public static void main(String[] args) 
	{
		Ticket t1 = new Ticket();
		Ticket t2 = new Ticket();
		t1.start();
		t2.start();
    }
}

注意:这个所谓的正确代码块,还是存在安全隐患的,因为如果线程0执行到num=1到了判断语句之后,这时如果线程1进来,那么会输出Thread=1…num=1,随后切换到线程0,输出就会为Thread=0…num=0

通过接口Runnable实现多线程

由于Java不允许多继承,所以当一个类已经有父类时就不能够继承Thread类了,这时要通过接口Runnable实现多线程。使用实现接口Runnable的对象创建线程,当启动线程时,在独立运行的线程中就会调用对象的run方法。

代码块

class ThreadDemo 
{
	public static void main(String[] args) 
	{
		Ticket t = new Ticket();
		// 使用实现Runnable接口的对象创建一个线程
		Thread t1 = new Thread(t);
		Thread t2 = new Thread(t);
		//启动该线程,将导致在独立运行的线程中调用该对象的run方法
		t1.start();
		t2.start();
	}
}
class Ticket implements Runnable
{
	public int num=100;
	public void run()
	{
		while(true)
		{
			if(num>0)
			System.out.println(Thread.currentThread().getName()+"..."+num--);
		}
	}
}

命令行运行结果为

最后要注意的几点:
1.上述实现多线程是不安全的,还需要通过同步关键字synchronized来保证安全。
2.实现多线程常见的有三种方式,这里介绍了通过继承Thread类实现,通过实现接口Runnable实现,最后一种我们有机会再说。

猜你喜欢

转载自blog.csdn.net/qq_29880477/article/details/84537900