一、每个java程序至少包含一个线程:主线程。其他线程都是通过Thread构造器或实例化继承类Thread的类来创建的。
public class MainThread {
//每个java程序至少包含一个线程:主线程。其他线程都是通过Thread构造器或实例化继承类Thread的类来创建的
public static void main(String[] args) {
//调用Thread类currentThread()方法获取当前线程
Thread t = Thread.currentThread();
System.out.println("主线程是:"+t);
}
}
二、继承Thread类
package com;
/**
*
* 解释结果:
* 主线程名:main
当前线程名:Thread-0
当前线程名:mythread
对于输出结构不仅不同机器之间的结果可能不同,而且在同一个机器上多次运行同一个程序也可能生成不同的结果,
* 这是因为线程的执行次序是不定的,由操作系统控制,除非使用同步机制按特定的顺序执行。
注意:
start()方法不能多次调用,如调用两次会抛出IllegalThreadStateException异常
*
*/
class Thread1 extends Thread{
@Override
public void run() {
System.out.println("当前线程名:"+Thread.currentThread().getName());
}
}
class Thread2 extends Thread{
public Thread2(String name) {
super(name);
}
@Override
public void run() {
System.out.println("当前线程名:"+Thread.currentThread().getName());
}
}
public class ThreadDemo {
public static void main(String[] args) {
System.out.println("主线程名:"+Thread.currentThread().getName());
Thread1 t1 = new Thread1();
Thread2 t2 = new Thread2("mythread");
t1.start();
t2.start();
//t2.start(); //不能两次调用否则会抛出异常
}
}
控制台输出
主线程名:main
当前线程名:Thread-0
当前线程名:mythread
三、实现Runnable接口实现线程
package com;
/**
* 实现Runnable接口创建线程
* 结果:随机产生结果
* @author Administrator
*
*/
class Renwu implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
for (int i = 0; i < 2000; i++) {
System.out.println("A");
}
}
}
public class RunnableDemo {
public static void main(String[] args) {
Renwu rw = new Renwu() ;
Thread t = new Thread(rw);
t.start();
System.out.println("主"+Thread.currentThread().getName());
for (int i = 0; i < 2000; i++) {
System.out.println("C");
}
}
}
结果产生随机,说明每个时刻随机执行一次线程。
四、线程的生命周期
新建:采用new语句执行创建完成。
就绪:执行start方法
运行:占用CPU
阻塞:执行了wait语句,执行了sleep语句和等待某个对象锁。等待输入的场合。
终止:退出run()方法。
package com;
class LifeThread1 extends Thread {
@Override
public void run() {
int i =0 ;
while((++i)<1000){
}
}
}
public class LifeThread {
public static void main(String[] args) throws InterruptedException {
LifeThread1 t1 = new LifeThread1() ;
System.out.println("等待状态"+t1.isAlive());
t1.start();
System.out.println("运行状态"+t1.isAlive());
//join方法是等待线程结束
t1.join();
System.out.println("线程结束"+t1.isAlive());
}
/*等待状态false
运行状态true
线程结束false*/
}
五、案例
package com;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class ButtonMove extends JFrame implements Runnable{
JPanel p ;
JButton btnStart ,btnStop,btnMove ;
Thread t ;
int movex=5 ;
public ButtonMove() {
p = new JPanel(null);
btnStart= new JButton("开始");
btnStop= new JButton("停止");
btnMove =new JButton("左右移动");
btnStart.setBounds(60,30,60,25);
btnStop.setBounds(130,30,60,25);
btnMove.setBounds(0,100,100,25);
p.add(btnStart);
p.add(btnStop);
p.add(btnMove);
this.add(p);
this.setSize(400,300);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//注册监听
btnStart.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
//创建线程对象
t = new Thread(ButtonMove.this);
//线程启动
t.start();
}
});
btnStop.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if(t.isAlive()){
//线程停止
t.stop();
}
}
});
}
@Override
public void run() {
while(t.isAlive()){
int x =btnMove.getX()+movex ;
int y = btnMove.getY();
if(x<=0){
x=0;
movex=-movex ;
}else if(x>=this.getWidth()-btnMove.getWidth()){
x=this.getWidth()-btnMove.getWidth();
movex=-movex ;
}
btnMove.setLocation(x,y);
try {
//休眠100毫秒
t.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public static void main(String[] args) {
ButtonMove f = new ButtonMove() ;
f.setVisible(true);
}
}
sleep方法
1 Thread.sleep(毫秒)。
2 该方法作用是阻塞当前线程,让出CPU资源,让给其他线程。进入阻塞状态
3
Interrupt()方法
打断休眠执行该方法会被catch到从而打断休眠
package com;
/**
* 需求: 打断睡眠。
* @author Administrator
*
*/
public class InterruptTest {
public static void main(String[] args) {
Processor p = new Processor() ;
p.setName("processor"); //设置线程名字
p.start();
p.interrupt(); //调用interrupt()方法会被catch到
}
}
class Processor extends Thread{
@Override
public void run() {
try {
Thread.sleep(10000000);
} catch (InterruptedException e) {
//e.printStackTrace();
}
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName()+""+i);
}
}
}
yield()方法
它与sleep()方法类似,只是不能由用户指定暂停多长时间,并且yield()方法只能让同优先级的线程有执行的机会。
当一个线程使用了这个方法之后,它就会把自己CPU执行的时间让掉,让自己或者其它的线程运行。
package com;
/**
* yield()方法
*
*/
class Thread1 extends Thread{
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName()+"---"+i);
if(i%20==0){
Thread1.yield();//让CPU片段 都有机会获取
}
}
}
}
class Thread2 extends Thread{
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName()+"---"+i);
}
}
}
public class ThreadDemo {
public static void main(String[] args) {
//System.out.println("主线程名:"+Thread.currentThread().getName());
Thread1 t1 = new Thread1();
t1.setName("tone");
Thread2 t2 = new Thread2();
t2.setName("two");
t1.setPriority(Thread.NORM_PRIORITY);
t2.setPriority(Thread.NORM_PRIORITY);
t1.start();
t2.start();
}
}
六、多线程案例
package com;
import java.awt.Color;
import java.awt.Font;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
/**
*
* 线程的最主要的功能是多任务处理,即多线程。多线程也就是在主线程中有多个线程在运行,多个线程的执行是‘并发’的
*
* tip: 什么是并发 并发:通过cpu调度算法,让用户看上去同时执行,实际上从cpu操作层面不是真正的同时。并发往往在场景中有公用的资源,
* 那么针对这个公用的资源往往产生瓶颈,我们会用TPS或者QPS来反应这个系统的处理能力
*
*/
public class MultiThreadDemo extends JFrame {
JPanel p;
JLabel lbl;
JButton btn;
String s[] = { "你好", "欢迎", "121工程", "软件外包" };
public MultiThreadDemo() {
super("多线程");
p = new JPanel();
lbl = new JLabel("颜色");
btn= new JButton(s[0]);
lbl.setFont(new Font("宋体", Font.BOLD, 20));
btn.setFont(new Font("黑体", Font.ITALIC, 20));
p.add(lbl);
p.add(btn);
this.add(p);
this.setSize(300, 200);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// 创建子线程
new ColorChange().start();
// 创建子线程
new TextChange().start();
}
class ColorChange extends Thread {
@Override
public void run() {
while (this.isAlive()) {
int r = (int) (Math.random() * 256);
int g = (int) (Math.random() * 256);
int b = (int) (Math.random() * 256);
lbl.setForeground(new Color(r, g, b));
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
class TextChange extends Thread {
@Override
public void run() {
int i = 0;
while (this.isAlive()) {
btn.setText(s[i++]);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if (i == s.length) {
i = 0;
}
}
}
}
public static void main(String[] args) {
MultiThreadDemo m = new MultiThreadDemo();
m.setVisible(true);
}
}
七、优先级别问题
package com;
/**
*
* 当有多个线程同时处于可执行状态并等待获得CPU时间时,线程调度系统根据各个线程的优先级来绝定CPU分配时间
* 优先级高的线程有“更大的机会”获得CPU时间
* 默认情况下 优先级是Thread.NORM_PRIORITY定义是5
* 可以通过set/getPriority()方法设置和获取 设置为MIN_PRIORITY(1) MAX_PRIORTY(10)之间
*
*注意:
*1当线程睡眠后,优先级别就失效了,若想保证优先级别继续有效 可以考虑使用join()方法解决 --等待线程结束
*2 线程优先级别依赖于操作系统,线程优先级别不能保证线程的执行次序,应尽量避免使用线程优先级为构建任务执行顺序的
*绝对标准
*/
class Mythread extends Thread{
public Mythread(String name) {
super(name);
}
@Override
public void run() {
System.out.println(this.getName());
try {
sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public class PriorityDemo {
public static void main(String[] args) {
Mythread t1 = new Mythread("first");
Mythread t2 =new Mythread("second");
Mythread t3 = new Mythread("third");
t1.setPriority(Thread.MAX_PRIORITY);
t2.setPriority(Thread.MAX_PRIORITY-1);
t3.setPriority(Thread.MAX_PRIORITY-3);
t1.start();
t2.start();
t3.start();
}
}
八、使用对象锁实现同步
package com;
/**
* JAVA使用监控器(对象锁)实现同步 ;每个对象都有一个对象锁。使用对象锁可以保证一次只允许一个线程执行对象的同步语句。
*
* 方式有两种
* 第一种是 修饰调用的方法 前面加上synchronized void print(String str)
* 第二种是 使用同步方法块修饰
* @Override
public void run() {
synchronized (s) {
s.print(str);
}
}
*
*注意:synchronized锁定的是对象,而不是方法或代码块;synchronized也可以修饰类,
*当用synchronized修饰 类的时候,表示这个类的所有方法都是synchronized的。
*/
class Share{
void print(String str){
System.out.println("["+str);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("]");
}
}
class Caller implements Runnable{
Thread t ;
String str ;
Share s ;
public Caller(String str, Share s) {
this.str = str;
this.s = s;
t = new Thread(this);
t.start();
}
@Override
public void run() {
synchronized (s) {
s.print(str);
}
}
}
public class NoSyn {
public static void main(String[] args) {
Share s = new Share() ;
Caller c1 = new Caller("客户A",s);
Caller c2 = new Caller("客户B",s);
Caller c3 = new Caller("客户C",s);
}
}
九、线程同步会造成的问题,使用notify()和wait()方法处理。
package com;
/**
* 线程同步会造成其他线程无法访问共享资源 ‘供需问题’
*
* wait()方法可以让线程等待,释放对象锁 notify()和notifyAll()方法使线程之间互相通知事件的发生。
*
* tip: wait()方法区别sleep wait会释放对象锁 而sleep不会
*
*/
class Product {
int n;
// 为true时表示有值可取,为false时表示需要放入新值
boolean valueSet = false;
synchronized void get() {
// 如果没有值,等待新值放入
if (!valueSet) {
try {
wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName() + "-GET()" + n);
// 将valueSet设置为false表示值已取
valueSet = false;
// 通知等待线程,放入新值
notify();
}
synchronized void put(int n) {
// 如果没有值,等待线程取值
if (valueSet) {
try {
wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
this.n = n;
// 将valueSet设置为true 表示值已放入
valueSet = true;
System.out.println(Thread.currentThread().getName() + "-PUT" + n);
// 通知等待线程,进行取值操作
notify();
}
}
class Prodcer implements Runnable {
Product prodcut;
public Prodcer(Product product) {
this.prodcut = product;
new Thread(this, "Proceduer").start();
}
@Override
public void run() {
int k = 0;
// 生产5次
for (int i = 0; i < 5; i++) {
prodcut.put(k++);
}
}
}
class Consumer implements Runnable {
Product prodcut;
public Consumer(Product product) {
this.prodcut = product;
new Thread(this, "Consumer").start();
}
@Override
public void run() {
// 消费5次
for (int i = 0; i < 5; i++) {
prodcut.get();
}
}
}
public class WaitDemo {
public static void main(String[] args) {
// 共享的生产/消费实例
Product product = new Product();
// 指定生产线程
Prodcer prodcer = new Prodcer(product);
// 指定消费线程
Consumer consumer = new Consumer(product);
}
}
十、死锁问题
package com;
/**
* 通过对象锁,可以很方便地实现数据同步,而对象锁引起的等候,很容易导致另一种问题-----‘死锁’
* 所谓死锁,是指两个或多个线程都在等待对方释放对象资源而进入的一种不可‘调节’的状态。在程序设计
* 中,死锁是无法预测或避开的,尽管这种情况并非经常出现,但一旦出现,程序的调试将变得异常艰难。
*
*
*/
public class DeadLockDemo implements Runnable {
private boolean flag ;
//使用obj1 和obj2模拟两个对象资源
static Object obj1 = new Object();
static Object obj2 = new Object();
@Override
public void run() {
String name =Thread.currentThread().getName();
System.out.println(name+"flag:"+flag);
/**
* 如果flag为true 先获取Obj1资源 等待500毫秒后获取Obj2资源
* 如果flag为false 先获取Obj2资源 等待500毫秒后获取Obj1资源
*/
if(flag){
synchronized (obj1) {
System.out.println(name+"休眠500毫秒,等待obj2");
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (obj2) {
System.out.println("获取obj2");
}
}
}else{
synchronized (obj2) {
System.out.println(name+"休眠500毫秒,等待obj1");
try {
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
synchronized (obj1) {
System.out.println("获取obj1");
}
}
}
}
public static void main(String[] args) {
DeadLockDemo d1 = new DeadLockDemo() ;
d1.flag=true ;
DeadLockDemo d2 = new DeadLockDemo() ;
d2.flag=false ;
Thread t1 = new Thread(d1);
Thread t2= new Thread(d2);
t1.start();
t2.start();
}
}