要了解线程,就必须了解进程,那么什么是进程?
进程:程序在处理机上执行时所发生的活动叫进程,进程是执行中的程序,是活动的实体,进程是“自包容”的运行程序,有自己的地址空间,简单的说,比如我的电脑打开了ppt和word2个程序,则这就相当于2个进程.
线程:线程是轻量级进程,是CPU使用的基本单元
线程属于某一个进程,一个进程中拥有一个或多个线程
多个线程共享同一个进程资源
多任务处理有两类
基于进程:计算机同时运行多个进程
基于线程:一个进程包含多个线程
特点:
各个进程需要分配它们自己独立的地址空间
进程间调用涉及的开销比线程间通信多
多个线程可共享相同的地址空间并且共同分享同一个进程
线程间的切换成本比进程间切换成本低
进程是重量级的、线程是轻量级的
JVM中的线程
-
当操作系统启动(javac、java、javaw等命令)JVM时就创建了一个进
程 -
JVM进程内至少包含了两个线程:main方法和垃圾回收线程,它们
称为主线程,有时它们还会启动其他线程,它们必须最后完成执行,
执行各种关闭、释放动作
在Java中,实现线程的方式有3种,
(1)声明一个 Thread 类的子类,并覆盖 run() 方法public class SampleThread extends Thread { public void run( ) {/* 覆盖该方法*/ } } }
(2)声明一个实现 Runnable 接口的类,并实现 run() 方法
public class SampleThread implements Runnable{
public void run( ) {
/* 实现该方法*/
}
}
(3)实现Callable接口,实现他的call方法;
import java.util.concurrent.Callable;
public class Thread<V> implements Callable<V>{
public V call() throws Exception {
// TODO Auto-generated method stub
return null;
}
}
Callable<V> oneCallable = new SomeCallable<V>();
//由Callable<Integer>创建一个FutureTask<Integer>对象:
FutureTask<V> oneTask = new FutureTask<V>(oneCallable);
//注释:FutureTask<Integer>是一个包装器,它通过接受Callable<Integer>来创建,它同时实现了Future和Runnable接口。
//由FutureTask<Integer>创建一个Thread对象:
Thread oneThread = new Thread(oneTask);
oneThread.start();
//至此,一个线程就创建完成了。
值得注意的是,第一种直接继承Thread类的方法,是直接重写了run方法,也就是将自己变成了线程; 而第二种方式自己本身并不是线程,它实现runnable接口后, 实现了其中的run方法,只是拥有了规定一个空线程如何run的能力.
2中方式的实例代码:
先定义2个线程; MyT1和 MyT2(请自己新建3个类将下面代码分开)
public class MyT1 extends Thread {
@Override
public void run() {
for(int i = 0; i < 1000; i++) {
System.out.println("aaaaa");
}
}
}
public class MyT2 extends Thread {
@Override
public void run() {
for(int i = 0; i < 1000; i++) {
System.out.println("bbbbb");
}
}
}
public class Run {
public static void main(String[] args) {
System.out.println("main开始!");
MyT1 t1 = new MyT1();
MyT2 t2 = new MyT2();
//设置线程优先级
t1.setPriority(1);
t2.setPriority(10);
t1.start();
t2.start();
System.out.println("main结束!");
}
}
第二种方式:
先定义2个线程; MyT1和 MyT2(请自己新建3个类将下面代码分开)
public class MyT1 implements Runnable {
@Override
public void run() {
try {
for(int i = 0; i < 10; i++) {
System.out.println("aaaaa");
Thread.currentThread().sleep(1000);
}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
//此处MyT2和MyT1采用不同的写法
public class MyT2 implements Runnable {
private Thread t = null;
public MyT2() {
this.t = new Thread(this);
this.t.start();
}
@Override
public void run() {
try {
for(int i = 0; i < 10; i++) {
System.out.println("bbbbb");
Thread.currentThread().sleep(2000);
}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public class Run {
public static void main(String[] args) {
System.out.println("main开始!");
//MyT1和MyT2的=run的方式也会有所不同
Thread t1 = new Thread(new MyT1());
t1.start();
new MyT2();
System.out.println("main结束!");
}
}
线程的状态
新建态(NEW) :至今尚未启动的线程处于这种状态
新创建的但未调用Thread.start()方法的线程处于该状态
运行态 (RUNNABLE) :可运行线程的线程状态,已经调用start方法
处于可运行状态的某一线程正在 Java 虚拟机中运行,但它 可能正在等待操作系统中的其他资源,比如处理器
锁定态(等待态) (BLOCKED) :受阻塞线程的线程状态
处于受阻塞状态的线程正在等待监视器锁,以便进入一个同
步的块/方法,或者在调用Object.wait()之后再次进入同步 的块/方法
锁定态又分为定时锁定(给定时间锁定)和不定时锁定(调用sleep方法)
中止态(TERMINATED):已终止线程的线程状态。线程 已经结束执行
二: 线程中的方法
1.sleep()方法
在指定时间内让当前正在执行的线程暂停执行,但不会释放“锁标志”。不推荐使用。sleep()使当前线程进入阻塞状态,在指定时间内不会执行。
2.wait()方法
在其他线程调用对象的notify或notifyAll方法前,导致当前线程等待。线程会释放掉它所占有的“锁标志”,从而使别的线程有机会抢占该锁。当前线程必须拥有当前对象锁。如果当前线程不是此锁的拥有者,会抛出IllegalMonitorStateException异常。
唤醒当前对象锁的等待线程使用notify或notifyAll方法,也必须拥有相同的对象锁,否则也会抛出IllegalMonitorStateException异常。waite()和notify()必须在synchronized函数或synchronized block中进行调用。如果在non-synchronized函数或non-synchronized block中进行调用,虽然能编译通过,但在运行时会发生IllegalMonitorStateException的异常。
3.yield方法
暂停当前正在执行的线程对象。yield()只是使当前线程重新回到可执行状态,所以执行yield()的线程有可能在进入到可执行状态后马上又被执行。yield()只能使同优先级或更高优先级的线程有执行的机会。
4.join方法
等待该线程终止。等待调用join方法的线程结束,再继续执行。如:t.join();//主要用于等待t线程运行结束,若无此句,main则会执行完毕,导致结果不可预测。
三:线程优先级(线程抢占CPU的能力)
如果不设置优先级,默认为5,Java提供1~10的优先级,1最低,10最高
设置优先级方法:
final void setPriority(int newp) //: 修改线程的当前优先级
final int getPriority() //: 返回线程的优先级
四: 线程同步
有时两个或多个线程可能会试图同时访问一个资源例如,一个线程可能尝试从一个文件中读取数据,而另一个线程则尝试在同一文件中修改数据在此情况下,数据可能会变得不一致;为了确保在任何时间点一个共享的资源只被一个线程使用,必须使用“同步”同步是指同时只能有一个线程访问同一个资源.
完成同步的2中方式:
(1)同步方法,
synchronized void methodA() { }
(2)同步块
synchronized(object) {
//要同步的语句
}
同步示例:
首先,新建3个类PrintM Student 和 Run
PrintM:
public class PrintM {
public void print(String info) {
System.out.print("[" + info);
try {
Thread.currentThread().sleep(1000);
System.out.println("]");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Student :
public class Student extends Thread {
private String name = null;
private PrintM pm = null;
public Student() {
// TODO Auto-generated constructor stub
}
public Student(String n, PrintM p) {
this.name = n;
this.pm = p;
}
@Override
public void run() {
synchronized(this.pm) {
this.pm.print(this.name);
}
}
}
除了这种方式(同步块),因为我们用一台打印机printM打印东西,故还可以将printM中的print方法加上同步块关键字synchronized,(也就是同步方法)
Run:
public class Run {
public static void main(String[] args) {
PrintM pm = new PrintM();
Student s1 = new Student("rose", pm);
Student s2 = new Student("jack", pm);
Student s3 = new Student("peter", pm);
s1.start();
s2.start();
s3.start();
}
}
何时用同步方法?同步块?
只有一种情况我们建议使用同步方法: 这个类是自己写的,并且这个类中的这个方法永远都要做同步处理,其他情况基本都使用同步块,有利于提高效率!
五: wait-notify机制(让多个线程协作做事情)
Java中线程间通讯只提供2种/操作,等wait()和叫醒notify((只通知离自己最近的线程))和notifyAll()(所有线程都唤醒做事情,但只能一个优先级最高的做,其余线程仍然等待)因为:
这三个方法只有在同步方法中才能用(这些方法是作为 Object 类中的 final 方法实现的)
示例代码:(生产(面包)数字,消费数字)
Number类:
public class Number {
private int num = -1;
private boolean numOk = false;
/**
* 生成数字方法
* @param n 生成的数字
*/
public synchronized void putNum(int n) {
if(numOk) {
try {
wait();
} catch (InterruptedException e) {
System.out.println("putNum()方法发生线程终断异常!");
e.printStackTrace();
}
}
this.num = n;
this.numOk = true;
System.out.println("生成数字:" + this.num);
// try {
// Thread.sleep(1000);
// } catch (InterruptedException e) {
// // TODO Auto-generated catch block
// e.printStackTrace();
// }
notifyAll();
}
/**
* 得到数字方法
* @return 得到的数字
*/
public synchronized void getNum() {
if(!numOk) {
try {
wait();
} catch (InterruptedException e) {
System.out.println("getNum()方法发生线程终断异常!");
e.printStackTrace();
}
}
System.out.println("得到数字:" + this.num);
this.numOk = false;
// try {
// Thread.sleep(1000);
// } catch (InterruptedException e) {
// // TODO Auto-generated catch block
// e.printStackTrace();
// }
notifyAll();
}
}
produce类:
/**
* 生成数字线程
*/
public class Produce implements Runnable {
private int i = 0;
private Number number = null;
public Produce(Number n) {
this.number = n;
Thread t = new Thread(this, "produce");
t.start();
}
public void run() {
for(int j = 0; j < 10; j++) {
this.number.putNum((i++) * 10);
}
}
}
Consume类:
/**
* 消费数字线程
*/
public class Consume implements Runnable {
private Number number = null;
public Consume(Number n) {
this.number = n;
Thread t = new Thread(this, "consume");
t.start();
}
public void run() {
for(int i = 0; i < 10; i++) {
this.number.getNum();
}
}
}
NumberRun类:
public class NumberRun {
public static void main(String[] args) {
Number number = new Number();
new Produce(number);
new Consume(number);
}
}
最后,送给大家一个用线程做的小玩意:javaswing+线程 大家可以运行玩玩哈!!
3个类:
BallPanel类:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
/**
* 绘制界类
* @author IBMT40
*
*/
public class BallPanel extends JFrame {
private JPanel mainPanel = new JPanel();
private JPanel operatePanel = new JPanel();
public BallPanel() {
Container c = this.getContentPane();
c.setLayout(new BorderLayout());
this.mainPanel.setBackground(Color.BLACK);
c.add(this.mainPanel, BorderLayout.CENTER);
JButton b1 = new JButton("开始");
b1.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
Ball b = new Ball(mainPanel);
b.start();
}
});
JButton b2 = new JButton("退出");
b2.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
System.exit(0);
}
});
this.operatePanel.add(b1);
this.operatePanel.add(b2);
c.add(this.operatePanel, BorderLayout.SOUTH);
this.setSize(400, 400);
this.setTitle("ball");
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setVisible(true);
}
}
Ball类:
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JPanel;
/**
* 绘制小球线程
* @author IBMT40
*
*/
public class Ball extends Thread {
private JPanel mainPanel = null;
private int x = 0;
private int y = 0;
private int dx = 5;
private int dy = 5;
private int width = 20;
private int height = 20;
public Ball(JPanel p) {
this.mainPanel = p;
}
public void run() {
init();
while(true) {
try {
Thread.sleep(20);
Graphics g = this.mainPanel.getGraphics();
g.setColor(Color.WHITE);
//g.setXORMode(this.mainPanel.getBackground());
g.setXORMode(Color.BLACK);
g.fillOval(this.x, this.y, this.width, this.height);
x = x + dx;
y = y + dy;
if(x > this.mainPanel.getWidth() - this.width) {
dx = -dx;
}
if(y > this.mainPanel.getHeight() - this.height) {
dy = -dy;
}
if(x < 0) {
x = 0;
dx = -dx;
}
if(y < 0) {
y = 0;
dy = -dy;
}
g.fillOval(x, y, this.width, this.height);
g.dispose();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
private void init(){
Graphics graphics = this.mainPanel.getGraphics();
graphics.setColor(Color.WHITE);
graphics.fillOval(x, y, this.width, this.height);
graphics.dispose();
}
}
BallRun类:
/**
* 主程序
* @author IBMT40
*
*/
public class BallRun {
public static void main(String[] args) {
new BallPanel();
}
}
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/96872.html