1.Java多线程
1.1基本概念:
程序:是为了完成特定任务、用某种语言编写的一组指令的集合。即指一段静态的代码,静态对象。
进程:是程序的一次执行过程,或是正在运行的一个程序。动态过程:有它自身的产生、存在和消亡的过程。
线程:进程可进一步细化为线程,是一个程序内部的一条执行路径。
若一个程序可以同一时间执行多个线程,就是支持多线程的。
1.2多线程好处:
提高应用程序的响应,对图形化界面更有意义,可增强用户体验。
提高计算机系统CPU的利用率。
改善程序结构,将既长又复杂的进程分为多个线程,独立运行,利于理解和修改。
1.3何时需要多线程:
程序需要同时执行两个或多个任务。
程序需要实现一些需要等待的任务时,如用户输入、文件读写操作、网络操作、搜索等。
需要一些后台运行的程序时。
1.4创建多线程的四种方式:
1.继承Thread类
2.实现Runnable接口
3.实现Callable接口
4.使用线程池
2.创建多线程的方式之一:继承Thread
start():启动线程,调用当前线程的run()
不能用调用 对象.run()的方式来启动线程。
一个线程只能启动一次。
如果需要创建多个线程,需要先创建多个对象,用不同的对象来启动线程。
package threadTest;
public class SubThread extends Thread{
// 1.创建主线程。
public static void main(String[] args) {
// 3.实例化Thread类的子类
SubThread s1 = new SubThread();
// 4.调用对象的start()
s1.start();
System.out.println("hello");
for(int i = 1 ;i <= 1000 ;i++ )
if(i%2 == 0)
System.out.println(i + "----------");
}
// 2.重写Thread类中的run(),将此线程要执行的操作,声明在run()的方法体中。
@Override
public void run(){
for(int i = 1 ;i <= 1000 ;i++ )
if(i%2 == 0)
System.out.println(i);
}
}
package threadTest;
/**
* 创建两个分线程,一个线程实现100以内的偶数的遍历,另一个线程实现100以内的基数遍历
*/
public class ThreadExer {
public static void main(String[] args) {
MyThread1 m1 = new MyThread1();
MyThread2 m2 = new MyThread2();
m1.start();
m2.start();
//创建Thread类的匿名子类的匿名对象。
new Thread(){
public void run(){
for(int i = 1 ;i <= 100;i++)
if(i%2==0)
System.out.println(Thread.currentThread().getName()+"====:"+i);
}
}.start();
}
}
class MyThread1 extends Thread{
@Override
public void run(){
for(int i = 1 ;i <= 100;i++)
if(i%2==0)
System.out.println(Thread.currentThread().getName()+"----:"+i);
}
}
class MyThread2 extends Thread{
@Override
public void run(){
for(int i = 1 ;i <= 100;i++)
if(i%2!=0)
System.out.println(Thread.currentThread().getName()+":"+i);
}
}
3.使用同步的方式和使用Lock的方式有什么异同?
同,都是解决线程安全问题的。
异,同步的方式,在执行完同步代码块或同步方法以后,会自动释放同步监视器。
Lock的方式,必须手动地执行unlock(),才可以释放。
package threadTest;
/**
* 生产者、消费者问题
* 生产者将产品交给店员。而消费者从店员处取走产品。
* 店员一次只能维持固定数量的产品(比如:20)如果生产者试图生产更多的产品,店员会叫生产者停一下。
* 如果店中有空位放产品了再通知生产者继续生产;如果店中没有产品了,店员会告诉消费者等一下,如果店中有产品了
* 再通知消费者取走产品。
*
* 分析:
* 是多线程问题;
* 存在线程安全问题;
* 共享数据是:产品的数量;
* 使用同步机制处理操作共享数据的安全问题;
* 涉及到了线程的通信问题。
*
*/
//店员
class Clerk{
int product;
//增加产品
public synchronized void addProduct(){
if(product < 20 ){
product++;
System.out.println(Thread.currentThread().getName()+ "生产了第"+product+"个产品");
notify();
}else{
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
//减少产品
public synchronized void reduceProduct(){
if(product > 0 ){
System.out.println(Thread.currentThread().getName()+ "消费了第"+product+"个产品");
product --;
notify();
}else{
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
//生产者
class Producer extends Thread{
Clerk clerk;
public Producer(Clerk clerk){
this.clerk = clerk;
}
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+":开始生产产品");
while(true){
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
clerk.addProduct();
}
}
}
//消费者
class Consumer extends Thread{
Clerk clerk;
public Consumer(Clerk clerk){
this.clerk = clerk;
}
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+":开始消费产品");
while(true){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
clerk.reduceProduct();
}
}
}
public class ProducerConsumerTest {
public static void main(String[] args) {
Clerk clerk = new Clerk();
Producer p1 = new Producer(clerk);
p1.setName("生产者1");
Consumer c1 = new Consumer(clerk);
c1.setName("消费者1");
Consumer c2 = new Consumer(clerk);
c2.setName("消费者2");
p1.start();
c1.start();
c2.start();
}
}
4.JVM的内存结构分析:
内存区域:方法区(Method Area),虚拟机栈(VM Stack),本地方法栈(Native Method Stack),堆(Heap),程序技术器(Program Counter Register)
5.String
5.1不可变性
给现有的字符串添加一个新的字符串,不能在原有的字符串后面添加,而必须声明一个新的内存空间,存放新的字符串。
给现有的字符串重新赋值,不能再原有的常量池对应的字符串的位置赋值,必须重新声明一个新的内存空间,存放新的字符串。
5.2连接运算
凡是字符串的连接运算中,左右两边使用了字符串的引用(而非字符串实体),此时的连接后的结果都应该在常量池中新开辟的内存空间。