文章较长,建议从目录选取感兴趣内容,然后Ctry+F搜索、跳转
01_多线程(多线程的引入)(了解)
02_多线程(多线程并行和并发的区别)(了解)
03_多线程(Java程序运行原理和JVM的启动是多线程的吗)(了解)
04_多线程(多线程程序实现的方式1)(掌握)
05_多线程(多线程程序实现的方式2)(掌握)
06_多线程(实现Runnable的原理)(了解)
07_多线程(两种方式的区别)(掌握)
08_多线程(匿名内部类实现线程的两种方式)(掌握)
09_多线程(获取名字和设置名字)(掌握)
10_多线程(获取当前线程的对象)(掌握)
11_多线程(休眠线程)(掌握)
12_多线程(守护线程)(掌握)
13_多线程(加入线程)(掌握)
14_多线程(礼让线程)(了解)
15_多线程(设置线程的优先级)(了解)
16_多线程(同步代码块)(掌握)
17_多线程(同步方法)(掌握)
18_多线程(线程安全问题)(掌握)
19_多线程(火车站卖票的例子用实现Runnable接口)(掌握)
20_多线程(死锁)(了解)
21_多线程(以前的线程安全的类回顾)(掌握)
22_多线程(单例设计模式)(掌握)
23_多线程(Runtime类)
24_多线程(Timer)(掌握)
25_多线程(两个线程间的通信)(掌握)
26_多线程(三个或三个以上间的线程通信)
27_多线程(JDK1.5的新特性互斥锁)(掌握)
28_多线程(线程组的概述和使用)(了解)
29_多线程(线程的五种状态)(掌握)
30_多线程(线程池的概述和使用)(了解)
31_多线程(多线程程序实现的方式3)(了解)
32_设计模式(简单工厂模式概述和使用)(了解)
33_设计模式(工厂方法模式的概述和使用)(了解)
34_GUI(如何创建一个窗口并显示)
35_GUI(布局管理器)
36_GUI(窗体监听)
37_GUI(鼠标监听)
38_GUI(键盘监听和键盘事件)
39_GUI(动作监听)
40_设计模式(适配器设计模式)(掌握)
--------------------------------------------------------正文----------------------------------------------------------------
A:Java程序运行原理
B:JVM的启动是多线程的吗
1.继承Thread
public class Demo2_Thread {
/**
* @param args
*/
public static void main(String[] args) {
MyThread mt = new MyThread(); //4,创建自定义类的对象
mt.start(); //5,开启线程
for(int i = 0; i < 3000; i++) {
System.out.println("bb");
}
}
}
class MyThread extends Thread { //1,定义类继承Thread
public void run() { //2,重写run方法
for(int i = 0; i < 3000; i++) { //3,将要执行的代码,写在run方法中
System.out.println("aaaaaaaaaaaaaaaaaaaaaaaaaaaa");
}
}
}
定义类实现Runnable接口
实现run方法
把新线程要做的事写在run方法中
创建自定义的Runnable的子类对象
创建Thread对象, 传入Runnable
调用start()开启新线程, 内部会自动调用Runnable的run()方法
public class Demo3_Runnable {
/**
* @param args
*/
public static void main(String[] args) {
MyRunnable mr = new MyRunnable(); //4,创建自定义类对象
//Runnable target = new MyRunnable();
Thread t = new Thread(mr); //5,将其当作参数传递给Thread的构造函数
t.start(); //6,开启线程
for(int i = 0; i < 3000; i++) {
System.out.println("bb");
}
}
}
class MyRunnable implements Runnable { //1,自定义类实现Runnable接口
@Override
public void run() { //2,重写run方法
for(int i = 0; i < 3000; i++) { //3,将要执行的代码,写在run方法中
System.out.println("aaaaaaaaaaaaaaaaaaaaaaaaaaaa");
}
}
}
查看源码的区别:
继承Thread
实现Runnable接口
继承Thread类
new Thread() { //1,new 类(){}继承这个类
public void run() { //2,重写run方法
for(int i = 0; i < 3000; i++) { //3,将要执行的代码,写在run方法中
System.out.println("aaaaaaaaaaaaaaaaaaaaaaaaaaaa");
}
}
}.start();
实现Runnable接口
new Thread(new Runnable(){ //1,new 接口(){}实现这个接口
public void run() { //2,重写run方法
for(int i = 0; i < 3000; i++) { //3,将要执行的代码,写在run方法中
System.out.println("bb");
}
}
}).start();
new Thread("xxx") {
public void run() {
for(int i = 0; i < 1000; i++) {
System.out.println(this.getName() + "....aaaaaaaaaaaaaaaaaaaaaaa");
}
}
}.start();
new Thread("yyy") {
public void run() {
for(int i = 0; i < 1000; i++) {
System.out.println(this.getName() + "....bb");
}
}
}.start();
Thread t1 = new Thread() {
public void run() {
for(int i = 0; i < 1000; i++) {
System.out.println(this.getName() + "....aaaaaaaaaaaaaaaaaaaaaaa");
}
}
};
Thread t2 = new Thread() {
public void run() {
for(int i = 0; i < 1000; i++) {
System.out.println(this.getName() + "....bb");
}
}
};
t1.setName("芙蓉姐姐");
t2.setName("凤姐");
t1.start();
t2.start();
new Thread(new Runnable() {
public void run() {
for(int i = 0; i < 1000; i++) {
System.out.println(Thread.currentThread().getName() + "...aaaaaaaaaaaaaaaaaaaaa");
}
}
}).start();
new Thread(new Runnable() {
public void run() {
for(int i = 0; i < 1000; i++) {
System.out.println(Thread.currentThread().getName() + "...bb");
}
}
}).start();
Thread.currentThread().setName("我是主线程"); //获取主函数线程的引用,并改名字
System.out.println(Thread.currentThread().getName()); //获取主函数线程的引用,并获取名字
Thread.sleep(毫秒,纳秒), 控制当前线程休眠若干毫秒1秒= 1000毫秒 1秒 = 1000 * 1000 * 1000纳秒 1000000000
new Thread() {
public void run() {
for(int i = 0; i < 10; i++) {
System.out.println(getName() + "...aaaaaaaaaaaaaaaaaaaaaa");
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}.start();
new Thread() {
public void run() {
for(int i = 0; i < 10; i++) {
System.out.println(getName() + "...bb");
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}.start();
Thread t1 = new Thread() {
public void run() {
for(int i = 0; i < 50; i++) {
System.out.println(getName() + "...aaaaaaaaaaaaaaaaaaaaaa");
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
Thread t2 = new Thread() {
public void run() {
for(int i = 0; i < 5; i++) {
System.out.println(getName() + "...bb");
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
t1.setDaemon(true); //将t1设置为守护线程
t1.start();
t2.start();
final Thread t1 = new Thread() {
public void run() {
for(int i = 0; i < 50; i++) {
System.out.println(getName() + "...aaaaaaaaaaaaaaaaaaaaaa");
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
Thread t2 = new Thread() {
public void run() {
for(int i = 0; i < 50; i++) {
if(i == 2) {
try {
//t1.join(); //插队,加入
t1.join(30); //加入,有固定的时间,过了固定时间,继续交替执行
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(getName() + "...bb");
}
}
};
t1.start();
t2.start();
使用synchronized关键字加上一个锁对象来定义一段代码, 这就叫同步代码块
多个同步代码块如果使用相同的锁对象, 那么他们就是同步的
class Printer {
Demo d = new Demo();
public static void print1() {
synchronized(d){ //锁对象可以是任意对象,但是被锁的代码需要保证是同一把锁,不能用匿名对象
System.out.print("黑");
System.out.print("马");
System.out.print("程");
System.out.print("序");
System.out.print("员");
System.out.print("\r\n");
}
}
public static void print2() {
synchronized(d){
System.out.print("传");
System.out.print("智");
System.out.print("播");
System.out.print("客");
System.out.print("\r\n");
}
}
}
使用synchronized关键字修饰一个方法, 该方法中所有的代码都是同步的
class Printer {
public static void print1() {
synchronized(Printer.class){ //锁对象可以是任意对象,但是被锁的代码需要保证是同一把锁,不能用匿名对象
System.out.print("黑");
System.out.print("马");
System.out.print("程");
System.out.print("序");
System.out.print("员");
System.out.print("\r\n");
}
}
/*
* 非静态同步函数的锁是:this
* 静态的同步函数的锁是:字节码对象
*/
public static synchronized void print2() {
System.out.print("传");
System.out.print("智");
System.out.print("播");
System.out.print("客");
System.out.print("\r\n");
}
}
多线程并发操作同一数据时, 就有可能出现线程安全问题
使用同步技术可以解决这种问题, 把操作数据的代码进行同步, 不要多个线程一起操作
public class Demo2_Synchronized {
/**
* @param args
* 需求:铁路售票,一共100张,通过四个窗口卖完.
*/
public static void main(String[] args) {
TicketsSeller t1 = new TicketsSeller();
TicketsSeller t2 = new TicketsSeller();
TicketsSeller t3 = new TicketsSeller();
TicketsSeller t4 = new TicketsSeller();
t1.setName("窗口1");
t2.setName("窗口2");
t3.setName("窗口3");
t4.setName("窗口4");
t1.start();
t2.start();
t3.start();
t4.start();
}
}
class TicketsSeller extends Thread {
private static int tickets = 100;
static Object obj = new Object();
public TicketsSeller() {
super();
}
public TicketsSeller(String name) {
super(name);
}
public void run() {
while(true) {
synchronized(obj) {
if(tickets <= 0)
break;
try {
Thread.sleep(10);//线程1睡,线程2睡,线程3睡,线程4睡
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(getName() + "...这是第" + tickets-- + "号票");
}
}
}
}
尽量不要嵌套使用
private static String s1 = "筷子左";
private static String s2 = "筷子右";
public static void main(String[] args) {
new Thread() {
public void run() {
while(true) {
synchronized(s1) {
System.out.println(getName() + "...拿到" + s1 + "等待" + s2);
synchronized(s2) {
System.out.println(getName() + "...拿到" + s2 + "开吃");
}
}
}
}
}.start();
new Thread() {
public void run() {
while(true) {
synchronized(s2) {
System.out.println(getName() + "...拿到" + s2 + "等待" + s1);
synchronized(s1) {
System.out.println(getName() + "...拿到" + s1 + "开吃");
}
}
}
}
}.start();
}
单例设计模式:保证类在内存中只有一个对象。
如何保证类在内存中只有一个对象呢?
单例写法两种:
//饿汉式
class Singleton {
//1,私有构造函数
private Singleton(){}
//2,创建本类对象
private static Singleton s = new Singleton();
//3,对外提供公共的访问方法
public static Singleton getInstance() {
return s;
}
public static void print() {
System.out.println("11111111111");
}
}
//懒汉式,单例的延迟加载模式
class Singleton {
//1,私有构造函数
private Singleton(){}
//2,声明一个本类的引用
private static Singleton s;
//3,对外提供公共的访问方法
public static Singleton getInstance() {
if(s == null)
//线程1,线程2
s = new Singleton();
return s;
}
public static void print() {
System.out.println("11111111111");
}
}
class Singleton {
private Singleton() {}
public static final Singleton s = new Singleton();//final是最终的意思,被final修饰的变量不可以被更改
}
Runtime r = Runtime.getRuntime();
//r.exec("shutdown -s -t 300"); //300秒后关机
r.exec("shutdown -a"); //取消关机
Timer类:计时器
public class Demo5_Timer {
/**
* @param args
* 计时器
* @throws InterruptedException
*/
public static void main(String[] args) throws InterruptedException {
Timer t = new Timer();
t.schedule(new MyTimerTask(), new Date(114,9,15,10,54,20),3000);
while(true) {
System.out.println(new Date());
Thread.sleep(1000);
}
}
}
class MyTimerTask extends TimerTask {
@Override
public void run() {
System.out.println("起床背英语单词");
}
}
A:线程组概述
MyRunnable mr = new MyRunnable();
Thread t1 = new Thread(mr, "张三");
Thread t2 = new Thread(mr, "李四");
//获取线程组
// 线程类里面的方法:public final ThreadGroup getThreadGroup()
ThreadGroup tg1 = t1.getThreadGroup();
ThreadGroup tg2 = t2.getThreadGroup();
// 线程组里面的方法:public final String getName()
String name1 = tg1.getName();
String name2 = tg2.getName();
System.out.println(name1);
System.out.println(name2);
// 通过结果我们知道了:线程默认情况下属于main线程组
// 通过下面的测试,你应该能够看到,默任情况下,所有的线程都属于同一个组
System.out.println(Thread.currentThread().getThreadGroup().getName());
// ThreadGroup(String name)
ThreadGroup tg = new ThreadGroup("这是一个新的组");
MyRunnable mr = new MyRunnable();
// Thread(ThreadGroup group, Runnable target, String name)
Thread t1 = new Thread(tg, mr, "张三");
Thread t2 = new Thread(tg, mr, "李四");
System.out.println(t1.getThreadGroup().getName());
System.out.println(t2.getThreadGroup().getName());
//通过组名称设置后台线程,表示该组的线程都是后台线程
tg.setDaemon(true);
// public static ExecutorService newFixedThreadPool(int nThreads)
ExecutorService pool = Executors.newFixedThreadPool(2);
// 可以执行Runnable对象或者Callable对象代表的线程
pool.submit(new MyRunnable());
pool.submit(new MyRunnable());
//结束线程池
pool.shutdown();
提交的是Callable
// 创建线程池对象
ExecutorService pool = Executors.newFixedThreadPool(2);
// 可以执行Runnable对象或者Callable对象代表的线程
Future f1 = pool.submit(new MyCallable(100));
Future f2 = pool.submit(new MyCallable(200));
// V get()
Integer i1 = f1.get();
Integer i2 = f2.get();
System.out.println(i1);
System.out.println(i2);
// 结束
pool.shutdown();
public class MyCallable implements Callable {
private int number;
public MyCallable(int number) {
this.number = number;
}
@Override
public Integer call() throws Exception {
int sum = 0;
for (int x = 1; x <= number; x++) {
sum += x;
}
return sum;
}
}
多线程程序实现的方式3的好处和弊端
好处:
弊端:
public class AnimalFactory {
private AnimalFactory(){}
//public static Dog createDog() {return new Dog();}
//public static Cat createCat() {return new Cat();}
//改进
public static Animal createAnimal(String animalName) {
if(“dog”.equals(animalName)) {}
else if(“cat”.equals(animale)) {
}else {
return null;
}
}
}
动物抽象类:public abstract Animal { public abstract void eat(); }
工厂接口:public interface Factory {public abstract Animal createAnimal();}
具体狗类:public class Dog extends Animal {}
具体猫类:public class Cat extends Animal {}
开始,在测试类中每个具体的内容自己创建对象,但是,创建对象的工作如果比较麻烦,就需要有人专门做这个事情,所以就知道了一个专门的类来创建对象。发现每次修改代码太麻烦,用工厂方法改进,针对每一个具体的实现提供一个具体工厂。
狗工厂:public class DogFactory implements Factory {
public Animal createAnimal() {…}
}
猫工厂:public class CatFactory implements Factory {
public Animal createAnimal() {…}
}
Frame f = new Frame(“my window”);
f.setLayout(new FlowLayout());//设置布局管理器
f.setSize(500,400);//设置窗体大小
f.setLocation(300,200);//设置窗体出现在屏幕的位置
f.setIconImage(Toolkit.getDefaultToolkit().createImage("qq.png"));
f.setVisible(true);
Frame f = new Frame("我的窗体");
//事件源是窗体,把监听器注册到事件源上
//事件对象传递给监听器
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
//退出虚拟机,关闭窗口
System.exit(0);
}
});