进程:
是一个正在执行中的程序。每一个进程执行都有一个执行顺序。该顺序是一个执行路径, 或者叫一个控制单元
线程:
是进程中的一个独立的控制单元。线程在控制着进程的执行。一个进程中至少要有一个 线程
Java vm 启动时会有一个进程java.exe
该进程在至少有一个线程负责java程序的执行
而且这个线程运行的代码在main方法中
创建线程:
Java提供了对线程这类事物的描述,就是Thread类。
创建线程的第一种方式:继承Thread类,复写run方法,
Thread类中的run方法,用于存储线程要运行的代码。
实例:
class XianCheng extends Thread
{
//复写run方法
public void run()
{
System.out.println("这是一个线程");
}
}
public class Test {
public static void main(String[] args) {
//建立线程对象
XianCheng xc = new XianCheng();
//调用start方法,开始线程
xc.start();
}
}
线程运行状态:
被创建:start()
运行时-->冻结:冻结状态放弃了CPU的执行权。
sleep(time),time时间到冻结结束
Wait()使线程冻结,notify()唤醒冻结的线程
运行时-->消亡:stop()
阻塞状态:具备执行资格,但没有执行权,等待CPU
创建线程的另一种方式:声明实现Runnable接口的类,该类实现run方法
代码示例:
class Ticket implements Runnable
{
//定义票数
private int tickets = 100;
//复写run方法
public void run() {
while (true)
{
if(tickets > 0)
{
System.out.println(Thread.currentThread().getName()+":"+tickets--);
}
}
}
}
public class TicketTest {
public static void main(String[] args) {
Ticket t = new Ticket();
//开启4个窗口
new Thread(t).start();
new Thread(t).start();
new Thread(t).start();
new Thread(t).start();
}
}
实现方式与继承方式的区别:
实现方式完成多线程的同时,还能继承其他类。避免了单继承的局限性
继承Thread类线程的代码存放在Thread子类的run方法中
实现Runnable线程的代码存在于接口的子类run方法中
多线程的安全问题:
当多条语句在操作同一个线程共享数据时,一个线程对多条语句只执行了一 部分,还没执行完,另一个线程参与进来执行,导致共享数据的错误。比如 上面的买票程序的例子就可能打印出0,-1,-2的票数
解决办法:
对多条操作共享数据的语句,只能让一个线程都执行完。在执行的过程 中,其他线程不可以参与执行。
Java对于多线程的安全问题提供了解决方法---同步代码块
上述程序代码run方法可修改为:
public void run() {
while (true)
{
synchronized(obj)
{
if(tickets > 0)
{
System.out.println(Thread.currentThread().getName()+":"+tickets--);
}
}
}
}
同步代码块对象如同锁。持有锁的线程可以在同步中执行。
没有持有锁的线程及时获取了cpu的执行权,也进不去,因为没有锁
同步的前提:
必须要有两个或者两个以上的线程
必须是多个线程使用同一个锁
同步的好处:
解决了多线程的安全问题
同步的弊端:
多个线成需要判断,消耗资源
同步synchronized还可以作为修饰符放在函数上,实现同步函数
|