进程:正在运行的程序
线程:执行路径
单线程程序:记事本
多线程程序:扫雷
多线程的实现方式:
package demo06;
/*
多线程的实现方法
1.定义Thread类重写run方法
2.创建Thread类的对象
3.启动多线程
*/
public class Demo01 {
public static void main(String[] args) {
MyThread my1=new MyThread();
MyThread my2=new MyThread();
my1.start();
my2.start();
}
}
package demo06;
/*
创建一个新的执行线程有两种方法。 一个是将一个类声明为一个Thread的子类。 这个子类应该重写Thread类的方法run 。
*/
public class MyThread extends Thread {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println(i);
}
}
}
设置和获取线程名称:
package demo06;
/*
设置和获取线程名称:
1.getName() 返回此线程的名称。
2.setName(String name) 将此线程的名称更改为等于参数 name 。
3.static Thread currentThread() 返回对当前正在执行的线程对象的引用。
*/
public class Demo01 {
public static void main(String[] args) {
MyThread my1=new MyThread();
MyThread my2=new MyThread();
my1.setName("飞机");
my2.setName("高铁");
my1.start();
my2.start();
System.out.println(Thread.currentThread());
}
}
package demo06;
/*
创建一个新的执行线程有两种方法。 一个是将一个类声明为一个Thread的子类。 这个子类应该重写Thread类的方法run 。
*/
public class MyThread extends Thread {
public void MyThread(){};
public void MyThread(String name){};
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println(getName()+":"+i);
}
}
}
多线程设置和获取优先级
package demo06;
/*
线程调度和线程优先级
1.int getPriority() 返回此线程的优先级。
2.void setPriority(int newPriority) 更改此线程的优先级。 优先级的范围1-10
注:优先级高只能表示调用CPU的几率高
*/
public class Demo01 {
public static void main(String[] args) {
MyThread my1=new MyThread();
MyThread my2=new MyThread();
MyThread my3=new MyThread();
my1.setName("飞机");
my2.setName("高铁");
my3.setName("汽车");
my1.setPriority(10);
my2.setPriority(5);
my3.setPriority(1);
my1.start();
my2.start();
my3.start();
}
}
线程控制sleep
package demo06;
/*
线程控制
1.static void sleep(long millis) 使当前正在执行的线程停留(暂停执行)指定的毫秒数,这取决于系统定时器和调度程序的精度和准确性。
*/
public class MyThread extends Thread {
public void MyThread(){};
public void MyThread(String name){};
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println(getName()+":"+i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
线程控制join:
package demo06;
/*
线程控制
2.void join() 等待这个线程死亡。
*/
public class Demo01 {
public static void main(String[] args) throws InterruptedException {
MyThread my1=new MyThread();
MyThread my2=new MyThread();
MyThread my3=new MyThread();
my1.setName("飞机");
my2.setName("高铁");
my3.setName("汽车");
my1.start();
my1.join();
my2.start();
my3.start();
}
}
线程控制3守护线程
package demo06;
/*
线程控制
3.void setDaemon(boolean on) 将此线程标记为 daemon线程或用户线程。 守护线程
*/
public class Demo01 {
public static void main(String[] args) throws InterruptedException {
MyThread my1=new MyThread();
MyThread my2=new MyThread();
MyThread my3=new MyThread();
my1.setName("关羽");
my2.setName("张飞");
//设置主线程
Thread.currentThread().setName("刘备");
//设置守护线程
my1.setDaemon(true);
my2.setDaemon(true);
my1.start();
my2.start();
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName()+","+i);
}
}
}
线程的生命周期
多线程的第二种实现方法:
package demo06;
/*
多线程的第二种实现方法:
1.定义一个类MyRunnable实现runnable接口
2.重写run方法
3.创建MyRunnable对象
4.创建Thread对象,将MyRunnable对象作为Thread对象的参数
5.启动线程
*/
public class Demo02 {
public static void main(String[] args) {
MyRunnable mr=new MyRunnable();
MyRunnable mr2=new MyRunnable();
Thread th1=new Thread(mr,"飞机");
Thread th2=new Thread(mr2,"高铁");
th1.start();
th2.start();
}
}
第二种方法的优点:
(1)解决java单继承的问题
(2)体现面向对象的思想,把线程和程序有效分离
卖票案例
package demo06;
/*
案例:卖票
*/
public class Demo03 {
public static void main(String[] args) {
SellTicket st=new SellTicket();
Thread th1=new Thread(st,"窗口1");
Thread th2=new Thread(st,"窗口2");
Thread th3=new Thread(st,"窗口3");
th1.start();
th2.start();
th3.start();
}
}
package demo06;
public class SellTicket implements Runnable {
private int ticket=100;
@Override
public void run() {
while (true){
if(ticket>0){
System.out.println(Thread.currentThread().getName()+"正在出售第"+ticket+"张票");
ticket--;
}
}
}
}
卖票案例的思考:
package demo06;
/*
案例:卖票案例的思考
使用Thread.sleep后
出现负数票和同一张票卖多次的现象
原因:线程的随机性
一票卖多次:在ticket--之前被另一个线程抢到CPU
负数票:在ticket--之后被另一个线程抢到CPU
*/
public class Demo03 {
public static void main(String[] args) {
SellTicket st=new SellTicket();
Thread th1=new Thread(st,"窗口1");
Thread th2=new Thread(st,"窗口2");
Thread th3=new Thread(st,"窗口3");
th1.start();
th2.start();
th3.start();
}
}
- 线程同步
synchronized解决数据安全问题:
package demo06;
public class SellTicket implements Runnable {
private int ticket=100;
Object obj=new Object();
@Override
public void run() {
while (true){
synchronized (obj){
if(ticket>0){
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"正在出售第"+ticket+"张票");
ticket--;
}
}
}
}}
优点:各个线程分开
缺点:各个线程都会去判断同步上的锁,耗费资源
同步方法的锁对象:this
package demo06;
public class SellTicket implements Runnable {
private int ticket=100;
private int x=0;
Object obj=new Object();
@Override
public void run() {
while (true){
if(x%2==0){
synchronized (this){
if(ticket>0){
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"正在出售第"+ticket+"张票");
ticket--;
}
}
}else{
sellTicket();
x++;
}
}}
private synchronized void sellTicket() {
if(ticket>0){
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"正在出售第"+ticket+"张票");
ticket--;
}
}
}
静态同步方法的锁对象:类名.class
package demo06;
public class SellTicket implements Runnable {
private static int ticket=100;
private int x=0;
Object obj=new Object();
@Override
public void run() {
while (true){
if(x%2==0){
synchronized (SellTicket.class){
if(ticket>0){
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"正在出售第"+ticket+"张票");
ticket--;
}
}
}else{
sellTicket();
x++;
}
}}
private synchronized static void sellTicket() {
if(ticket>0){
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"正在出售第"+ticket+"张票");
ticket--;
}
}
}
线程安全的类:
package demo06;
import java.util.*;
/*
线程安全的类
StringBuffer
Vector
Hashtable
*/
public class Demo04 {
public static void main(String[] args) {
StringBuilder sb=new StringBuilder();
StringBuffer sbb=new StringBuffer();
Vector<String> ve=new Vector<>();
ArrayList<String> arr=new ArrayList<>();
Hashtable<String,String> ht=new Hashtable<>();
HashMap<String,Integer> hm=new HashMap<>();
//更常用的static <T> List<T> synchronizedList(List<T> list) 返回由指定列表支持的同步(线程安全)列表。
List<String> strings = Collections.synchronizedList(new ArrayList<String> ());
}
}
Lock锁:
package demo06;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/*
lock的使用:
void lock() 获得锁。
void unlock() 释放锁。
构造方法:ReentrantLock() 创建一个 ReentrantLock的实例。
*/
public class SellTicket implements Runnable {
private int ticket=100;
private Lock lock =new ReentrantLock();
@Override
public void run() {
while (true){
try{
lock.lock();
if(ticket>0){
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"正在出售第"+ticket+"张票");
ticket--;
}
}finally {
lock.unlock();
}
}
}
}
生产者和消费者模式概述:
Object类中的等待和唤醒方法:
1.void wait() 导致当前线程等待,直到另一个线程调用该对象的 notify()方法或 notifyAll()方法。
2.void notify() 唤醒正在等待对象监视器的单个线程。
3.void notifyAll() 唤醒正在等待对象监视器的所有线程。
?案例:生产者和消费者案例