垃圾回收
public class Demo01Thread {
/*
* 进程:电脑中正在运行的程序
* 正在开工的工厂
*
* 线程:电脑中正在运行的程序中正在执行的代码块
* 开工的工厂中正在运作的流水线
*
* 线程是进程执行单元
* 线程是代码块在内存中的执行空间
* 一个进程至少包含一个线程
* 一个进程中有多个线程在执行---多线程、线程并发
*
* 线程(英语:thread)是操作系统能够进行运算调度的最小单位。
* 它被包含在进程之中,是进程中的实际运作单位。
* 一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。
*
* 感受一下多线程:
* 一个类要运行必须有main方法::虚拟机在运行一个类时 会为此类的main方法创建一个线程(main线程)
* 为此线程分配执行空间 来运行main方法中的代码
* 平常的类运行是由两个线程在并行执行:
* main线程--执行main方法中的代码
* 垃圾回收相关的线程---专门用于垃圾回收相关代码的线程
*
*java来源:从c语言++ --而来
*添加了面向对象+垃圾回收
*java垃圾回收机制:虚拟机会不定时的启动垃圾回收器对象,垃圾回收器对象会根据内存中的对象是否存在更多引用
* 来判断此对象是否为垃圾 如果是垃圾就调用对象的finalize()方法 销毁对象释放内存
* 程序员可以通过System.gc()来干涉垃圾回收器机制 来主动启动垃圾回收器
*
* 多线程原理: CPU在时间轮片内只执行一个线程的代码 时间轮片到期 在多个线程之间随机切换
* 时间轮片:时间单位--25ms
*
* java支持多线程:通过Thread类创建线程
*
* */
public static void main(String[] args) {
// TODO Auto-generated method stub
// System.out.println(111);
// hehe();
for (int i = 0; i <20; i++) {
new Teacher();
}
System.gc();//主动启动垃圾回收器
for (int i = 0; i < 1000; i++) {
for (int j = 0; j <10; j++) {
if(i%100==0&&j==4) {
System.out.println("main方法 i="+i);
}
}
}
}
// public static void hehe() {
// Object o=new Object();
// }
}
class Teacher{
public final int num;
private static int n;
public Teacher() {
n++;
num=n;
}
@Override
public String toString() {
return "Teacher [num=" + num + "]";
}
@Override
protected void finalize() throws Throwable {
System.out.println(this+"的finalize方法被调用了!");
super.finalize();
}
}
Thread 线程
/*
* 进程:电脑中正在运行的程序
* 正在开工的工厂
*
* 线程:电脑中正在运行的程序中正在执行的代码块
* 开工的工厂中正在运作的流水线
*
* 线程是进程执行单元
* 线程是代码块在内存中的执行空间
* 一个进程至少包含一个线程
* 一个进程中有多个线程在执行---多线程、线程并发
*
* 线程(英语:thread)是操作系统能够进行运算调度的最小单位。
* 它被包含在进程之中,是进程中的实际运作单位。
* 一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。
*
* 感受一下多线程:
* 一个类要运行必须有main方法::虚拟机在运行一个类时 会为此类的main方法创建一个线程(main线程)
* 为此线程分配执行空间 来运行main方法中的代码
* 平常的类运行是由两个线程在并行执行:
* main线程--执行main方法中的代码
* 垃圾回收相关的线程---专门用于垃圾回收相关代码的线程
*
*java来源:从c语言++ --而来
*添加了面向对象+垃圾回收
*java垃圾回收机制:虚拟机会不定时的启动垃圾回收器对象,垃圾回收器对象会根据内存中的对象是否存在更多引用
* 来判断此对象是否为垃圾 如果是垃圾就调用对象的finalize()方法 销毁对象释放内存
* 程序员可以通过System.gc()来干涉垃圾回收器机制 来主动启动垃圾回收器
*
* 多线程原理: CPU在时间时间轮片内只执行一个线程的代码 时间轮片到期 在多个线程之间随机切换
* 时间轮片:时间单位--25ms
*
* java支持多线程:通过Thread类创建线程
*
* */
创建线程
/*
* Thread:
* 构造方法:
* Thread()
* 不指定线程名字,自动生成的名称的形式为 "Thread-"+n,其中的 n 为整数。
* Thread(String name)
* 参数是线程名字
* Thread(Runnable target)
* Thread(Runnable target, String name)
普通方法:
void setName(String name) :设置线程名字
String getName() :获取线程名字
void start() : 驱动线程 jvm才会为此线程分配执行空间 然后调用当前线程的run方法 执行线程任务
void run() : 线程任务封装
static void sleep(long millis) :线程休眠指定毫秒
static Thread currentThread() :获取当前线程
* 创建线程的方式一:
* 一种方法是将类声明为 Thread 的子类。该子类应重写 Thread 类的 run 方法。接下来可以分配并启动该子类的实例
* 1: 创建类继承Thread类
* 2: 重写run方法
* (重写的要求:除了范围修饰符可以扩大 抛出的异常可以少、小 其他方法声明必须和父类完全相同)
* 3: 创建自定义线程对象
*
* 总结:继承Thread 重写run
*
*
* */
代码:
public static void main(String[] args) {
//3 :创建自定义线程对象
MyThread2_1 m1=new MyThread2_1();
m1.setName("自定义线程1111");//给线程起个名字
//4:启动线程
m1.start();//此时有两个线程:::main线程和m1线程
new MyThread2_1("自定义线程22222222").start();
//此时有三个线程:::main线程和m1线程和m2线程
for (int i = 0; i < 10; i++) {
char c=(char)(Math.random()*26+'a');
Thread t=Thread.currentThread();//获取当前线程
System.out.println(t.getName()+"线程 打印字母的线程:::c="+c);
//线程休眠:
try {Thread.sleep(100); } catch (Exception e) {throw new RuntimeException(e); }
}
}
}
//1: 创建类继承Thread类
class MyThread2_1 extends Thread{
public MyThread2_1() {}
public MyThread2_1(String name) {
super(name);
}
//2: 重写run方法:当前线程要执行的代码块
public void run() {
for (int i = 0; i < 10; i++) {
char c=(char)(Math.random()*10+'0');
System.out.println(Thread.currentThread().getName()+" 打印数字的线程:::c="+c);
//线程休眠:
try {Thread.sleep(100); } catch (Exception e) {throw new RuntimeException(e); }
}
}
}
* 创建线程的方式二:
* 声明实现 Runnable 接口的类。该类然后实现 run 方法。然后可以分配该类的实例,在创建 Thread 时作为一个参数来传递并启动
* 1: 创建Runnable的实现类
* 2: 实现run方法:封装线程任务
* 3: 创建实现类对象
* 4:创建线程对象 并通过构造方法参数关联实现类对象
* 5:启动线程
*
* 总结:实现Runnable接口 实现run方法
代码:
public static void main(String[] args) {
//3: 创建实现类对象
MyRunnable mr=new MyRunnable();
//4:创建线程对象 并通过构造方法参数关联实现类对象
Thread t1=new Thread(mr);
t1.setName("线程111");
//5:启动线程
t1.start();
Thread t2=new Thread(mr,"线程222222");
//5:启动线程
t2.start();
for (int i = 0; i < 10; i++) {
char c=(char)(Math.random()*26+'a');
Thread t=Thread.currentThread();//获取当前线程
System.out.println(t.getName()+"线程 打印字母的线程:::c="+c);
//线程休眠:
try {Thread.sleep(100); } catch (Exception e) {throw new RuntimeException(e); }
}
}
}
//1: 创建Runnable的实现类
class MyRunnable implements Runnable{
//2: 实现run方法:封装线程任务
public void run() {
for (int i = 0; i < 10; i++) {
char c=(char)(Math.random()*10+'0');
System.out.println(Thread.currentThread().getName()+" 打印数字的线程:::c="+c);
//线程休眠:
try {Thread.sleep(100); } catch (Exception e) {throw new RuntimeException(e); }
}
}
}
继承Thread 类重写run方法创建三个线程
public class Demo04 {
//创建三个线程分别打印大写 小写 数字
public static void main(String[] args) {
//3 创建线程对象
//4 开启线程
new ThreadPrint("大写线程---", 'A', 26).start();
new ThreadPrint("小写线程++++++++", 'a', 26).start();
new ThreadPrint("数字线程!!!!!!!!!", '0', 10).start();
}
}
//一个方法中可以使用的变量:成员变量,方法体中的局部变量,参数列表
//1 继承Thread类
class ThreadPrint extends Thread{
ThreadPrint(String name,char startChar, int fw){
super(name);
this.startChar=startChar;this.fw=fw;
}
private char startChar;private int fw;//定义成员变量记录范围和起始值
//2 重写run方法
public void run() {
for (int i = 0; i <20; i++) {
char c=(char)(Math.random()*fw+startChar);
System.out.println(this.getName()+":::"+i+" "+c);
try {Thread.sleep(100);} catch (Exception e) {throw new RuntimeException(e);}
}
}
}
实现Runnable接口实现run方法创建三个线程:
//创建三个线程分别打印大写 小写 数字
public static void main(String[] args) {
//3 创建实现类对象:三个线程的线程任务不同 需要创建三个实现类对象
MyRunnablePrint pdx=new MyRunnablePrint('A', 26);
MyRunnablePrint pxx=new MyRunnablePrint('a', 26);
MyRunnablePrint psz=new MyRunnablePrint('0', 10);
//4 创建线程对象 与实现类对象关联
Thread tA=new Thread(pdx, "大写线程---");
Thread ta=new Thread(pxx, "小写线程------");
Thread t1=new Thread(psz, "数字线程----------");
//5启动线程
ta.start();tA.start();t1.start();
}
}
//1 创建Runnable的实现类
class MyRunnablePrint implements Runnable{
private char startChar;private int fw;//定义变量传递随机范围和起始值
MyRunnablePrint(char startChar, int fw){
this.startChar=startChar;this.fw=fw;
}
//2 实现run方法
public void run() {
for (int i = 0; i <20; i++) {
char c=(char)(Math.random()*fw+startChar);
System.out.println(Thread.currentThread().getName()+":::"+i+" "+c);
try {Thread.sleep(100);} catch (Exception e) {throw new RuntimeException(e);}
}
}
}
创建线程两种方式的优缺点
/*创建线程的两种方式:
* 1 继承Thread类 重写run方法
* 2 实现Runnable接口 实现run方法
*比较优缺点:
*
* 继承Thread类优点步骤简单 容易;理解
* 实现Runnable接口优点:
* 1 Runnable的实现类是对线程任务的封装 更符合java完全面向对象的思想
* 2 java只支持类与类的单继承 继承Thread后 无法再扩展
* java支持类实现多个接口 并且不影响继承其他类 实现Runnable后 不影响类的扩展
*总结:工作过程中建议使用方式2
*
* 完全面向对象:每个独立的功能 尽量都封装为独立的部件/对象
*
* /
模拟通过实现Runnable接口创建的Thread对象调用Runnable接口实现类的run方法的过程
public static void main(String[] args) {
}
//模拟Runnable
interface MyRunnable1{
void run();
}
//模拟Thread
class MyThread{
private MyRunnable1 r;
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
MyThread(){name="Thread_"+0;}
MyThread(MyRunnable1 r){
this.r=r;
name="Thread_"+0;
}
MyThread(String name){this.name=name;}
MyThread(MyRunnable1 r,String name){
this.r=r;
this.name=name;
}
public void run() {
System.out.println("线程任务:::Thread自带的run方法");
}
public void start() {
//线程开启 虚拟机自动调用当前线程的run方法
if(r!=null) {
r.run();
}else {
this.run();
}
}
}
join()
/*public final void join()
* 在a线程任务中调用b线程的join方法 a线程会等待 直到b线程执行完毕 b线程才继续执行
* 两个线程:一个对应30个数字 一个打印30个小写字母 要求打印数字的打印到5时 必须等待对应小写的执行完才能继续执行
*
*/
public static void main(String[] args) {
ThreadPrintSZ tsz=new ThreadPrintSZ();
tsz.setName("打印数字---");
ThreadPrintXX tXX=new ThreadPrintXX();
tXX.setName("打印小写-------");
tXX.start();
tsz.t=tXX;//给ThreadPrintSZ的t属性赋值
tsz.start();
//tsz.start();
}
}
class ThreadPrintSZ extends Thread{
ThreadPrintXX t;
public void run() {
for (int i = 0; i <30; i++) {
char c=(char)(Math.random()*10+'0');
System.out.println(Thread.currentThread().getName()+":::"+i+"::::"+c);
try {Thread.sleep(100);} catch (Exception e) {throw new RuntimeException(e);}
//判断随机的字符是不是5 如果是5 就调用tXX的join方法
if(c=='5') {
try {t.join();} catch (Exception e) {throw new RuntimeException(e);}
}
}
}
}
class ThreadPrintXX extends Thread{
public void run() {
for (int i = 0; i <30; i++) {
System.out.println(Thread.currentThread().getName()+":::"+i+"::::"+(char)(Math.random()*26+'a'));
try {Thread.sleep(100);} catch (Exception e) {throw new RuntimeException(e);}
}
}
}
线程死锁
1.join实现线程死锁
public class Demo01DieLock {
/*
* 线程死锁:多线程无法继续执行
* 死锁情况1: 两个线程互相调用对方的join方法
*
* */
public static void main(String[] args) {
// TODO Auto-generated method stub
TestDie t1=new TestDie();t1.setName("线程111");
TestDie t2=new TestDie();t2.setName("线程2222222");
t1.t=t2;t2.t=t1;
t1.start();t2.start();
}
}
class TestDie extends Thread{
Thread t;//定义引用记录要等待的线程对象
public void run() {
while(true) {
System.out.println(getName()+"::::"+System.currentTimeMillis());
//try {Thread.sleep(10);} catch (Exception e) {throw new RuntimeException(e);}
try {t.join();} catch (Exception e) {throw new RuntimeException(e);}
}
}
}
2.synchronized [ˈsɪŋkrənaɪzd] 实现线程死锁
public class Demo04DieLock {
/*线程死锁:通过synchronized实现线程死锁
* 两个线程:每个线程ab都有两个互相嵌套的同步代码块
* a线程的外锁 作为b线程的内锁 让a线程的内锁作为b线程外锁
*
* */
public static void main(String[] args) {
Object a=new Object();Object b=new Object();
ThreadDie t1=new ThreadDie();
t1.wai=a;t1.nei=b;
ThreadDie t2=new ThreadDie();
t2.wai=b;t2.nei=a;
t1.start();t2.start();
}
}
class ThreadDie extends Thread{
Object nei;Object wai;
public void run() {
while(true) {
System.out.println(getName()+"无锁状态!");
synchronized (wai) {
System.out.println(getName()+"拿到其外锁++:"+wai);
synchronized (nei) {
System.out.println(getName()+"拿到其内锁++++:"+nei);
}
System.out.println(getName()+"放开了其内锁---------:"+nei);
}
System.out.println(getName()+"放开了其外锁---------------:"+wai);
}
}
}
synchronized 同步锁
public class Demo02 {
/*线程安全问题: 多个线程的多个语句操作共享数据时 出现前后数据不一致的现象
*解决线程安全问题:当某个线程在使用共享数据过程中 如果其他线程也要使用共享数据 就等待
*通过同步代码块来解决线程安全问题:
* synchronized(对象){
* 操作共享数据的语句
* }
*注意1: 同步代码块必须包含了所有操作共享数据的代码
*注意2:synchronized的对象--锁对象---类型可以是任意类型
*注意3:多个线程的锁对象必须是同一个锁对象
*
*
*/
public static void main(String[] args) {
WindowThread2 w11=new WindowThread2();w11.setName("窗口1");
WindowThread2 w12=new WindowThread2();w12.setName("窗口12222");
WindowThread2 w13=new WindowThread2();w13.setName("窗口133333333");
Train2 tt=new Train2();
w11.t=tt;
w12.t=tt;
w13.t=tt;
w11.start();
w12.start();w13.start();
}
}
//定义类 描述火车
class Train2{
public int num=1;
}
//定义类 描述窗口:多个窗口卖票 之间互不影响 需要定义为线程类
class WindowThread2 extends Thread{
public Train2 t;
//static Object obj=new Object();//定义一个对象记录锁对象
public void run() {
//Object obj=new Object();
while(true) {
//Object obj=new Object();
synchronized (t) {
if(t.num<=100) {
System.out.println(Thread.currentThread().getName()+" 卖了一张票 票号是:"+t.num);
try {Thread.sleep(50);} catch (Exception e) {throw new RuntimeException(e);}
t.num++;
}else {
break;
}
}
try {Thread.sleep(50);} catch (Exception e) {throw new RuntimeException(e);
}
}
}
synchronized同步方法
public class Demo03 {
/*
* 同步方法:当一个方法的方法体要求同步时 可以把此方法定义为同步方法---加修饰符synchronized
* 同步方法的锁对象是this
* 静态同步方法的锁对象是当前类的Class文件:::类名.class
* */
//2 新生入校:一个线程登记:学生姓名+性别(给对象的属性赋值) 一个线程打印:姓名和性别
public static void main(String[] args) {
Person p=new Person();
ThreadWrite tw=new ThreadWrite();
ThreadPrint tp=new ThreadPrint();
tw.p=p;tp.p=p;
tw.setName("负责登记的线程");
tp.setName("负责打印的线程");
tw.start(); tp.start();
}
}
class Person{
char sex;
String name;
public synchronized void set(boolean b) {//同步方法:同步方法的锁是this
if(b) {
this.sex='男';this.name="tom";
}else {
this.sex='女';this.name="韩梅梅";
}
}
public static synchronized void hehe() {
}
}
//两个线程类 公用一个person
class ThreadWrite extends Thread{
Person p;
public void run() {
boolean b=true;
while(true) {
// synchronized (p) {
if(b) {
p.sex='男';p.name="tom";
}else {
p.sex='女';p.name="韩梅梅";
}
// //p.set(b);//set方法的所有代码需要完全设置到同步代码块中 这样的方法可以设置为同步方法
// }
//p.set(b);
if(Math.random()>0.5) {
synchronized (p) {
if(b) {
p.sex='男';p.name="tom";
}else {
p.sex='女';p.name="韩梅梅";
}
}
}else {
p.set(b);
}
b=!b;
try {Thread.sleep(50);} catch (Exception e) {throw new RuntimeException(e);}
}
}
}
class ThreadPrint extends Thread{
Person p;
public void run() {
while(true) {
synchronized (p) {
System.out.print(this.getName()+"::::"+p.name);
try {Thread.sleep(50);} catch (Exception e) {throw new RuntimeException(e);}
System.out.println("::::"+p.sex);
}
try {Thread.sleep(50);} catch (Exception e) {throw new RuntimeException(e);}
}
}
}
void wait()
让当前线程等待:失去拿锁的资格 失去cpu随机的资格
void notify()
随机唤醒一个正在等待的线程
代码实例:
public class Demo05ShaoBing {
/*
* 怎么实现做一个 吃一个
* Object类中的方法:
* void wait() : 当前线程等待:失去拿锁的资格 失去cpu随机的资格
* void notify(): 随机唤醒一个正在等待的线程
*
*
* */
public static void main(String[] args) {
ShaoBing shb=new ShaoBing();
SaleThread st=new SaleThread();st.setName("武大郎1");
SaleThread st2=new SaleThread();st2.setName("武大郎222");
EatThread et=new EatThread();et.setName("吃货33333号");
EatThread et2=new EatThread();et2.setName("吃货444444444号");
st.shb=shb;st2.shb=shb; et.shb=shb; et2.shb=shb;
st.start(); st2.start(); et.start(); et2.start();
}
}
class ShaoBing{
int number;
boolean b=false;//定义变量记录是否有烧饼
}
//一个线程做烧饼
class SaleThread extends Thread{
ShaoBing shb;
public void run() {
while(true) {
synchronized (shb) {
if(!shb.b) {
System.out.println(getName()+"开始做烧饼++++"+(shb.number+1));
try {Thread.sleep(50);} catch (Exception e) {}
shb.number++;
System.out.println(getName()+"做完了烧饼++++"+shb.number);
shb.b=true;//有烧饼
shb.notifyAll();//唤醒吃烧饼的线程
}else {
try {shb.wait();} catch (Exception e) {}//当前线程等待
}
}
try {Thread.sleep(5);} catch (Exception e) {}
}
}
}
//一个线程吃烧饼
class EatThread extends Thread{
ShaoBing shb;
public void run() {
while(true) {
synchronized (shb) {
if(shb.b) {
System.out.println(getName()+"开始吃烧饼--------"+shb.number);
try {Thread.sleep(10);} catch (Exception e) {}
System.out.println(getName()+"吃完了烧饼--------"+shb.number);
shb.b=false;
shb.notifyAll();//唤醒做烧饼的线程
}else {
try {shb.wait();} catch (Exception e) {}//当前线程等待
}
}
try {Thread.sleep(20);} catch (Exception e) {}
}
}
}