目录
一、基本概念
1.1 程序
静态的。
是对数据描述和操作代码的集合,是应用程序执行的脚本。
1.2 进程(Process)
动态的。
是程序的一次执行过程,是系统运行程序的基本单位。
一个进程包括操作系统分配的内存空间、包含一个或多个线程。
1.3 线程
动态的。
是程序中相对独立的代码段,比进程更小的运行单位,多个线程构成一个进程。
1.4 多线程
在Java中,一个应用程序可以包含多个线程。每个线程执行特定的任务,并可以与其他线程并发执行。
多线程使系统的空转时间最少,提高CPU的利用率。
多线程编程环境用方便的模型隐藏CPU在任务间切换的事实。
多线程能够满足程序员编写高效率的程序来达到充分利用CPU的目的。
1.5 进程与线程的区别
进程有独立的内存和CPU。线程需要依附于进程。进程大,线程小。
进程之间的切换消耗资源多,效率低。
线程之间的切换消耗资源少,效率高。
进程:
进程由操作系统管理,系统可以为一个程序创建多个进程。
进程有自己的内存空间和CPU空间。
进程基于的多任务程序独立开发、独立运行,但切换通信成本大,占用资源多。
线程:
线程是由进程调度管理的,多个线程构成一个进程。
线程没有自己独立的内存空间和CPU时间,只能依附于进程。
基于线程的多任务程序通信成本低,调用资源少,但不能独立开发运行。
1.6 线程的生命周期
新建 new线程实例
就绪 调用start()方法
运行 线程抢到CPU,开始运行run()方法中的代码
可能存在--阻塞field()、挂起suspend()、睡眠sleep()、等待wait()
死亡 run()方法中的代码执行完毕,或用stop(),destroy()函数强制终止
1.7 线程的状态
二、Java中线程的使用
java.lang.Thread类-----------java线程类
线程类简单使用:
public static void main(String[] args) {
//java程序运行时,至少有两条线程:main线程、system.gc(垃圾回收)线程[守护线程]
//得到当前的线程--main方法的线程
Thread thread = Thread.currentThread();
System.out.println("线程名称="+thread.getName()); //线程名称=main
System.out.println("线程ID="+thread.getId()); //线程ID=1
//线程的优先级1-10,默认为5,最高为10,最低为1
System.out.println("线程优先级="+thread.getPriority()); //线程优先级=5
System.out.println("线程最高优先级="+Thread.MAX_PRIORITY); //线程最高优先级=10
}
2.1 自定义线程的两种方式
1)extends Thread ,重写run()
2)implements Runnable ,重写run() --推荐方法,单继承多实现
2.2 启动线程
通过线程的实例调用start()方法,让线程进入 "就绪" 状态
进入就绪状态的线程,具备使用CPU的能力
如果就绪状态的线程获得CPU的使用权,则开始运行
如果就绪状态的线程没有获得CPU的使用权,则排队等待
2.3 实例
线程的两种定义方式即启动使用。
package com.company.mythread;
//自定义线程 继承java.lang.Thread类
public class MyThread1 extends Thread{
public void run() {
// 模拟长动作
for (int i = 0; i < 100; i++)
if(i%2==0){
System.out.println(i+"是偶数"); //线程1 输出0-100的偶数
//通过代码的方式交出CPU
try { Thread.sleep(1);} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
package com.company.mythread;
// 自定义线程实现Runnable接口 implements Runnable
public class MyThread2 implements Runnable {
//必须实现接口的run()方法
public void run() {
for (int i = 0; i < 100; i++) {
if(i%2==1) {
System.out.println(i+"是奇数"); //线程2 输出0-100的奇数
//通过代码的方式交出CPU
try { Thread.sleep(1); } catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
public class TestThread {
public static void main(String args[]) {
//启动自定义的线程
MyThread1 myThread1 = new MyThread1();
myThread1.start();
//调用start()方法启动线程,线程进入就绪状态
//就绪的线程则具备的排队使用CPU的能力
//当线程获得CPU时,就会运行
//如果没有获得CPU,继续排队等待
new Thread(new MyThread2()).start();
// MyThread2()--使用实现接口的方法创建
// 建议使用--单继承多实现
}
}
输出结果:(不唯一)
7. 线程同步
线程同步--加锁,数据安全,效率低。
线程不同步--无锁,数据不安全,效率高。
在Java中获得线程同步:synchronized
1)同步方法 <访问修饰符> synchronized <返回值类型> methodA(){ //需要同步的代码 }
2)同步块 synchronized (object){ //需要同步的代码,object一般使用this,传入当前对象即可 }
同步实例:四个人抢购100张票。
// Tickets类
public class Tickets {
private int count;
public void saler() {
System.out.println("票号"+count);
count++;
}
}
// 买票系统--同步方法
public class SalerTicket implements Runnable{
private int count; //票数
public SalerTicket(int count) {
this.count = count;
}
public void run() {
String name = Thread.currentThread().getName();
while(count<=100) {
methodA(name); //调用同步方法
Thread.yield(); //购买一次票后阻塞该线程
}
}
public synchronized void methodA(String name) { //同步方法
System.out.println(name+"买了票"+count);
count++; //票自增1
}
}
//买票系统--同步块实现
public class SalerTicket implements Runnable{
private int count; //票数
public SalerTicket(int count) {
this.count = count;
}
public void run() {
String name = Thread.currentThread().getName();
while(count<=100) {
synchronized (this) { //同步块,传入object--this
System.out.println(name+"买了票"+count);
count++;
}
Thread.yield();
}
}
}
// 主函数--购票
public class SalerTest {
public static void main(String[] args) {
int count=1; //起始票号
SalerTicket salerTicket = new SalerTicket(count);
// 使用四个线程抢票
new Thread(salerTicket,"人员1").start();
new Thread(salerTicket,"人员2").start();
new Thread(salerTicket,"人员3").start();
new Thread(salerTicket,"人员4").start();
}
}
// 运行购票
8.线程间的通信
8.1 wait-notify机制
为了避免轮流检测,Java提供了线程间通信机制--wait-notify机制,使用wait(),notify()和notifyAll()方法。
这些方法为Object类的final方法,只能在synchronized方法或synchronized块中使用。
wait()--告知被调用的线程退出监视器并进入等待状态,直到其他相同线程进入相同的监视器并调用notify()方法。
notify()--通知同一对象上第一个调用wait()的线程。
notifyAll()--通知调用wait()的所有线程,具有最高优先级的线程将先运行。
8.2练习 仓库货物存取问题
货物存取:高于20个,取货;低于5个进货
// 货物仓库类
public class Store {
private int count = 0; //初始货物数量
//放货物
public void put() {
synchronized (this) {
if(count < 20) {//货物数量小于20,放货物
count++;
System.out.println("进货,存货:"+count);
}else {// 货物充足,调用wait()
try { wait(); } catch (InterruptedException e) {
e.printStackTrace();
}
}
notify();//唤醒其他线程工作
}
}
//取货物
public void get() {
synchronized(this) {
if(count > 5) { //货物充足
System.out.println("取货:"+count);
count--;
}else { //货物不够
try { wait(); } catch (InterruptedException e) {
e.printStackTrace();
}
}
notify();//唤醒其他线程工作
}
}
}
//存放货物类
public class StorePutter implements Runnable{
private Store store;
public StorePutter(Store store) { //构造函数
this.store = store;
}
public void run() { //重写run()方法
while(true) {
store.put(); //不停放货
}
}
}
//取出货物类
public class StoreGetter implements Runnable{
private Store store;
public StoreGetter(Store store) { //构造函数
this.store = store;
}
public void run() { //重写run()方法
while(true) {
store.get(); //不停取货
}
}
}
//测试主函数
public class StoreTestMain {
public static void main(String[] args) {
Store store = new Store(); //Store实例
new Thread(new StorePutter(store)).start(); //放货线程
new Thread(new StoreGetter(store)).start(); //取货线程
}
}
运行: