多线程基础知识
进程与线程
进程是资源分配的最小单位,线程是CPU调度的最小单位。做个简单的比喻:
进程=火车,
线程=车厢线程在进程下行进(单纯的车厢无法运行)
一个进程可以包含多个线程(一辆火车可以有多个车厢)
不同进程间数据很难共享(一辆火车上的乘客很难换到另外一辆火车,比如站点换乘)
同一进程下不同线程间数据很易共享(A车厢换到B车厢很容易)
进程要比线程消耗更多的计算机资源(采用多列火车相比多个车厢更耗资源)
并发与并行
并行:两个任务在同一时刻互不干扰的
同时
执行。如游泳赛道上不同道的选手
同时
在游泳。
并发:同一段时间内两个任务发生,有前后顺序。如:2s内,裁判开枪,运动员跳入水中,这两个事件在极短时间内都发生了,但
不是同时
发生,是有先后的。
画图面板设计
首先看一下效果,每次点击start可以画一条线,一条线还没有画完的时候,可以点击start再画一条,实现多线程画图的效果。
首先需要设计一个面板来显示画的图。下面是代码
使用JFrame画一个面板,设置好标题大小等信息后,新建一个按钮“Start”,把按钮加入面板,设置流式布局,但要每点击一次出现画图效果,我们还要使用监听器,并具体设计监听器的代码,编写我们想要的效果。
ButtonListener这个类就是我们要写画图效果的地方。画图必须要有画笔,我们要把JFrame中获取的画笔传给ButtonListener。
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionListener;
public class UI {
public static void main(String[] args) {
UI ui = new UI();
ui.initUI();
}
public void initUI(){
JFrame jf = new JFrame();
jf.setTitle("ball game");
jf.setSize(1100,1100);
jf.setLocationRelativeTo(null);
jf.setDefaultCloseOperation(3);
jf.setLayout(new FlowLayout());
JButton jb = new JButton("Start");
jf.add(jb);
jf.setVisible(true);
ButtonListener listener = new ButtonListener(jf.getGraphics());
jb.addActionListener(listener);
}
}
监听器设计
按钮对应的监听器是ActionListener接口,我们必须写一个类来继承这个接口,再重写里面的actionPerformed方法,在方法里写我们自己想要的效果。下面是代码。UI类中传过来的画笔赋给当前ButtonListener类的画笔,此时,如果我们直接在actionPerformed里设置循环写代码,会发现,必须等一条线画好了,才可以继续按按钮话第二条线,这不符合我们想多线程画图的需求,此时我们需要设计一个MyThread类,来开启多线程,实现并发画图。
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class ButtonListener implements ActionListener {
private Graphics g;
public ButtonListener(Graphics g) {
this.g = g;
}
@Override
public void actionPerformed(ActionEvent e) {
MyThread myThread = new MyThread(g);
myThread.start();
}
}
线程类设计
下面是MyThread类的设计思路:首先继承Thread线程类,重写run方法,里面写我们想让该线程干的事情,但是记住再调用MyThread类时,
必须用start方法才可以实现多线程
。(也就是上面的 myThread.start();这一句代码)初始化一个画笔,用于传给ButtonListener的监听器方法,再按按钮时画图,因为要画多条线,每次就要随机一个起始横坐标点x,然后设置循环,不断画圆,每次y方向增加一个单位,连起来就是一条线的效果了。Thread.sleep(10);这条语句是为了设置线程休眠,让我们能清晰地看到计算机画圆的过程。注意,每次用这个方法是必须
捕获异常
。
import javax.swing.*;
import java.awt.*;
public class MyThread extends Thread{
private Graphics g ;
private int x,y=80,size = 50;
public MyThread(Graphics g) {
this.g = g;
x = (int)(Math.random()*1100);
System.out.println("x = "+x);
}
@Override
public void run() {
for (int i = 0; i < 1000; i++) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
// g.drawImage(image.getImage(),x,y,null);
g.fillOval(x,y++,50,50);
System.out.println(x+"正在执行");
}
}
}