1.创建一个线程
方式一:继承Thread类。
步骤:
1,定义一个类继承Thread。
2,复写Thread类中的run方法。
3,将自定义代码存储在run方法。让线程运行。
4,调用线程的start方法,可以开启线程。
示例代码:
class ManyThread extends Thread
{
public void run()
{
}}
}
方式二 实现Runnable接口并覆盖run方法
步骤
class MyThread implements
{
public void run()
{
}}
main(){
}
实现方式和继承方式有什么区别
多线程的运行出现了安全问题
解决的办法
synchronized(对象)
{
}
同步的前提
好处
弊端
如果存在安全问题,怎么找问题
同步函数用的是哪个锁呢
同步静态函数用的是哪个锁
2.终止线程
stop方法已经过时。
如何停止线程?
只有一种,run方法结束。
开启多线程运行,运行代码通常是循环结构。
只要控制住循环,就可以让run方法结束,也就是线程结束。
特殊情况:
当线程处于了冻结状态。
就不会读取到标记。那么线程就不会结束。
当没有指定的方式让冻结的线程恢复到运行状态是,这时需要对冻结进行清除。
强制让线程恢复到运行状态中来。这样就可以操作标记让线程结束。
Thread类提供该方法 interrupt();
3.守护进程
class zczthread implements Runnable
{
}
class main
{
public static void main(String[] args)
{
}
}
守护线程即后台线程
当所有前台线程都结束时,后台线程自动结束
也就是说 当所有线程都为守护线程时,java虚拟机退出
线程唤醒机制
wait()
notify()
notifyAll()
都使用在同步中,因为要对持有监视器(锁)的线程操作
所以要使用在同步中,因为只有同步才具有锁
为什么这些操作线程的方法要定义在Object类中?
只有同一个锁上的被等待线程,可以被同一个锁notify唤醒
不可以对不同的锁中的线程进行唤醒
也就是,等待与唤醒必须要是同一个锁
而锁可以是任意对象,所以可以被任意对象调用的方法定义在Object类中
在单CPU的硬件平台下,某一时刻只能有一个线程在运行,线程是由操作系统调度的。
启动一个线程不能直接调用run()方法,这样不会创建一个新的线程,只是简单的在当前线程中
执行了run()方法,
而应该调用start()方法,这样就会创建一个新的线程,在这个新的线程上执行run()方法上的
代码。
当run()方法执行完后,线程也就相应的结束,我们可以通过控制run()方法中循环的条件来控
制线程的结束。
(一个进程里面的多个线程都是无规律的交替运行)
Thread类中的setDaemon(true)设置一个线程为后台线程,该方法必须在线程启动之前调用,也
就是在调用start()方法之前调用。
如果一个进程中只有后台线程在运行,这个进程就会结束。
thread1.join()的作用是把thread1所对应的线程合并到调用thread1.join()的线程中。
yield()方法可以让当前正在运行的线程对象临时暂停,让别的线程运行。
sleep(...)方法可以让当前正在运行的线程进入睡眠状态。
获取和更改线程的优先级分别用Thread对象的getPriority()方法和setPriority(int
newPriority)方法。线程的默认优先级的值是5。
创建一个线程类有两种方法:
1,直接继承Thread类;
2, 实现Runnable接口,然后用new Thread(实现Runnable接口的类的对象)来产生一个线程类。
使用Runnable接口创建多线程,适合多个相同程序代码的线程去处理同一份资源的情况。还可
以避免由于java的单继承特性带来的局限。
事实上,几乎所有的多线程应用都可用Runnable接口方式。
每个线程都会有一个运行的时间片,都会有开始和时间片到期的时候。
所以我们要注意了:一个线程的时间片到期的时候,此线程有可能执行到程序的任何一个位置
而被暂停,并没有完全执行完一个原子性的模块,
然后就进入时间片的轮换,这样就导致多线程的运行结果不可意料。此时我们就需要对线程进
行同步处理。
线程同步关键字是:synchronized
同步代码块放在如下的大括号中:
synchronized(obj){ //用于synchronized的obj叫lock旗标(锁旗标),可以是任何对象,
我们通常称之为同步对象或者监视器对象。
}
同步方法只须在方法前加synchronized关键字修饰即可。
同步非静态方法的监视器是this,而同步静态方法的监视器是当前所在的类的Class对象。
只要使用相同的同步对象(监视器),synchronized方法和synchronized代码块也可以实现同步
。
在编写多线程同步的时候一定要注意避免死锁的发生。
String str1 = "";
String str2 = "";
while(true) {
synchronized(str1) {
...
synchronized(str2){
...
}
...
}
}
while(true) {
synchronized(str2) {
...
synchronized(str1){
...
}
...
}
}
如果上面的两个while块里面的代码分别由两个线程执行,那么就形成了死锁。
我们在编写线程安全的程序代码的时候也必须防止一个线程对共享的数据仅仅做了部分的操作
的时候,这个线程就结束了,这种情况下就会破坏数据的一致性。
要实现同步的线程所检查的监视器对象必须是同一个对象,才能保证线程的同步。
不同的类中的方法或者语句块也可以实现同步,只要是同一个监视器对象就可以了。
多线程编程里面的run()方法里面通常都是一个while循环程序。
Object类里面有几个方法是用于线程通信的:wait(),notify(),notifyAll()。由于任何对象
都可以作为监视器对象,所以任何对象都可以调用这几个方法。
但是这些方法只能在被synchronized修饰的方法或者代码块中调用。
每个对象除了有一个锁旗标之外,还有一个线程等待队列(wait set),一个对象刚创建的时
候,它的等待队列是空的。
如果一个线程里面有while循环,我们可以设置一个boolean flag变量作为while的循环条件,
while(flag),
当我们需要结束这个线程的时候就可以在另外一个线程中将这个flag设置为false即可。
但是有时候我们还需要结合interrupt()方法来结束一个线程,见如下例子:
package com.heima.exam;
class StopThreadTest {
public static void main(String[] args) {
ThreadInStop t1 = new ThreadInStop();
t1.start();
int index = 0;
while(true) {
if(index++ == 500){
t1.stopThread();
t1.interrupt();
break;
}
System.out.println(Thread.currentThread().getName());
}
System.out.println("main() exit");
}
}
class ThreadInStop extends Thread {
private boolean bStop = false;
public synchronized void run() {
while(!bStop) {
try {
wait();
} catch(InterruptedException e) {
if(bStop) {
return;
}
}
System.out.println(getName());
}
}
public void stopThread() {
bStop = true;
}
}