浅谈多线程那点事儿

一、基本概念

阅读本文前呢,先明确几个概念:1.什么是程序?2.什么是进程?3.什么是线程?4.什么是多线程。

1.程序通俗的讲呢就是一段指令序列集以及一些数据文件,存储在磁盘中。

2.进程通俗的讲就是正在运行的程序,由操作系统分配运行时所需要的资源,进程存储在内存中。

3.线程其实就是进程的细分,线程是进程的一个个独立运行单位,也是最小的执行单位。

4.多线程顾名思义就是一个进程里面由多个线程。线程呢并不是操作系统维护和管理的,而是由JVM(亦即Java虚拟机)创建并启动的。

二、细节说明

1.线程是在哪里执行的呢?

线程是在CPU里执行的,而执行过程的数据存放在离CPU较远的地方,根据操作系统原理,离CPU比较近的地方有一个叫高速缓存的区域,一般是三个。进程需要的资源会被预先读取到高速缓存中,当CPU指令到达时就会从高速缓存里面读取数据到CPU。所以当有指令对进程所需要的数据进行修改时,改变的只是缓存中的数据,而不是改变内存中的数据,所以切记注意这个问题。还有就算多线程读取数据问题,下面的多线程抽奖小程序(抽两个号码同时滚动显示),如果不考虑这个问题的话,就会看到滚动的数字只显示了一个,另一个数组要抽奖停下时才显示。解决的办法就是加关键字volatile,加载控制线程是否执行的变量前,如boolean类型的flag。或者另一个解决办法就算让进程休眠一段时间, 当然它会抛出异常。(2018.7.24补充更详细的sleep机制),sleep是Thread里面的一个静态方法,可以让正在被调用的线程暂停(或者叫挂起),即不是停止也不是退出。使用方法:Thread.sleep(long time),方法的参数是以毫秒为单位的,time即为你要线程暂停的时长,time一过,VM调用该线程回到正常状态。当线程在Sleep状态,如果VM或者其它线程强制终止这个线程,sleep方法就会抛出InterruptedException异常,也就是线程的中断异常,所以我们在用sleep方法的时候要特别注意这个异常的处理(代码一般会自动补全的)。

2.多线程的实现方式:

多线程实现的方式有两种,一种是用Thread类,另一种是Runnable接口
 将你要执行的代码或者方法调用写入run()方法即可,然后在使用start()方法启动你的线程。嗯是的,使用多线程就这两步!很简单吧2333。

3.抽奖小程序设计说明:

想必都看过抽奖的过程,就是随机出现一些号码并滚动显示。从这两点我们可以得出要使用的知识有随机数、一个循环来实现数字的滚动效果。设计抽奖小程序的界面就不细说了,看前面图形界面的博客,如果有不懂的。首先我的思路是添加两个按钮,一个是开始抽奖的,另一个是结束抽奖的。既然要按钮来控制抽奖,那监听器是少不了的。刚刚说了把要执行的代码写入run方法,所以我可以数字滚动的代码写入run方法里面即可。实现数字滚动其实就是更换它显示的数字而已,那么你可以随机不停的画出来,或者你可以用两个Label组件,不停的更好它显示的内容即可。前面说了用boolean的flag来控制抽奖的开始,那么当star按钮被按下的时候将flag置为true即可,stop按钮被按下时将flag置为false即可。

4.详细代码:

首先是界面的代码:

import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;

public class Lucky_Draw {

	public static void main(String[] args) {
		
		Lucky_Draw  L = new Lucky_Draw();
		L.Init();

	}
	public JLabel Label_one,Label_two,Label_thr;
	
	
	public void Init()
	{
		JFrame JF = new JFrame();
		JF.setTitle("腾讯幸运大抽奖!");
		JF.setSize(600, 700);//窗体的大小
		JF.setLocationRelativeTo(null);//窗体在屏幕显示的位置居中
		JF.setDefaultCloseOperation(3);//关闭的方式
		JF.setResizable(false);//是否可设置窗体的大小
		JF.setLayout(new FlowLayout(FlowLayout.CENTER,0,0));//组件居中
		
		Label_one = new JLabel("Luck Number:");
		Label_one.setPreferredSize(new Dimension (250,190));
		Label_one.setFont(new Font("宋体",Font.BOLD,30));
		JF.add(Label_one);
		
		Label_two = new JLabel("0");
		Label_two.setPreferredSize(new Dimension (160,160));
		Label_two.setFont(new Font("宋体",Font.BOLD,30));
		JF.add(Label_two);
		
		Label_thr = new JLabel("0");
		Label_thr.setPreferredSize(new Dimension(160,160));
		Label_thr.setFont(new Font("宋体",Font.BOLD,30));
		JF.add(Label_thr);
		
		JButton button_one = new JButton("Star");
		button_one.setPreferredSize(new Dimension(60,30));
		JF.add(button_one);
		
		JButton button_two = new JButton("Stop");
		button_two.setPreferredSize(new Dimension(60,30));
		JF.add(button_two);
		
		JF.setVisible(true);
		
		ButtonListener BL = new ButtonListener(Label_two,Label_thr);
		button_one.addActionListener(BL);
		button_two.addActionListener(BL);
	}
	

}

多线程+按钮监听:

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;

import javax.swing.JLabel;

public class ButtonListener  extends Thread implements ActionListener{
	
	public JLabel Label_two,Label_thr;
	public volatile boolean flag =false;//控制抽奖的开关
	public Random random = new Random();
	public ButtonListener(JLabel Label_two,JLabel Label_thr)
	{
		this.Label_two = Label_two;
		this.Label_thr = Label_thr;
		this.start();//启动线程
	}

	public void actionPerformed(ActionEvent e)
	 {
		 if(e.getActionCommand().equals("Star"))
		 {
			 flag = true;
		 }
		 if(e.getActionCommand().equals("Stop"))
		 {
			 flag = false ;
		 }
			
	 }

	public void run()//重写线程的内容,也就是你要执行的代码
	{	
		System.out.println("Flag:"+flag);
		while(true) //为了省去休眠,我直接让这个线程一直运行着,但还有一个开关来控制抽奖
		{
			
			if(flag==true)
			{
				Label_two.setText(random.nextInt(10)+" ");
				Label_thr.setText(random.nextInt(10)+" ");
				
			}
		}
	}

}
/*  现在我们分析一下为什么要在变量singleton之间加上volatile关键字。要理解这个问题,先要了解对象的构造过程,实例化一个对象其实可以分为三个步骤:
(1)分配内存空间。
(2)初始化对象。
(3)将内存空间的地址赋值给对应的引用。
但是由于操作系统可以对指令进行重排序,所以上面的过程也可能会变成如下过程:
(1)分配内存空间。
(2)将内存空间的地址赋值给对应的引用。
(3)初始化对象
如果是这个流程,多线程环境下就可能将一个未初始化的对象引用暴露出来,从而导致不可预料的结果。因此,为了防止这个过程的重排序,我们需要将变量设置为volatile类型的变量。
*/

上面是关于volatile关键字的详细说明。

最后贴一个抽奖小程序的界面:有点丑2333

猜你喜欢

转载自blog.csdn.net/weixin_42294984/article/details/81156561